Stepwise UI

Quick Start

Three steps from an empty project to a Stepwise component on screen. The middle one does the configuring for you.

Requirements

React 19, Tailwind CSS v4, TypeScript, and Node 18 or newer for the CLI.

Any React setup works. The steps below use Next.js because it is the common case.

1. Start a project

Skip this if you already have one.

npx create-next-app@latest my-app --typescript --tailwind --app
cd my-app

2. Run init

One command does the rest: it configures the project if it needs it, then lets you pick components and installs them.

npx stepwise-ui init

Type to filter, Tab to select, Enter to confirm. Whatever you pick is written into the project and its npm packages installed. Run it again any time you want more.

$ npx stepwise-ui init

┌  Stepwise UI
│
◆  Pick components to add
│  toast
│  ◻ toast        Global notification toasts in four types.
│  ◻ theme-toggle A button that switches between light and dark mode.
│
│  ↑/↓ to navigate • Tab: select • Enter: confirm • Type: to search
└

  ✓ components/stepwise/toast.tsx

  Installing: clsx, motion, tailwind-merge

✓ 1 component, 1 file written.

Before installing, it checks the two things components need: the dark-mode variant in your stylesheet and the @/ alias in tsconfig.json. If either is missing it offers to add it and asks first. Say no and it prints what to add yourself.

Adding the alias rewrites tsconfig.json as standard JSON, which drops any comments in it and reformats the rest. If yours is hand-tuned, decline and add the alias from the path alias below instead.

Already know the name? Skip the picker:

npx stepwise-ui add button

add installs components but never edits your config, because it runs unattended in scripts and agent sessions. See CLI for the rest of the commands.

3. Use it

import { Button } from '@/components/stepwise/button'

export default function Page() {
  return <Button variant="solid">Ship it</Button>
}

That is the whole setup. Every other component works the same way.

What init sets up

For reference, or if you would rather do it by hand. These are the two changes init offers to make.

The dark variant

Open your global stylesheet (app/globals.css in a fresh Next.js app) and add the @custom-variant line:

@import "tailwindcss";

/* Stepwise uses a class-based dark variant. Tailwind v4 defaults to
   prefers-color-scheme, so without this line every dark: class in the
   components does nothing. */
@custom-variant dark (&:where(.dark, .dark *));

Components render fine without it, but every dark-mode style is silently inert, which is confusing to debug later.

The path alias

Components are written to components/stepwise/ and lib/, and import each other through the @/ alias. create-next-app sets this up already:

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./*"]
    }
  }
}

Theme provider

Optional. Components render correctly without it. You need ThemeProvider only for a working light/dark toggle - it manages the dark class on <html> and remembers the choice. It is written to lib/theme.tsx with your first component.

import { ThemeProvider } from '@/lib/theme'

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en" suppressHydrationWarning>
      <body>
        <ThemeProvider>{children}</ThemeProvider>
      </body>
    </html>
  )
}

Border colour

Every squircle border in the library reads one variable, so you can retint all of them at once. Components carry a neutral grey as the built-in value - define --ui-border anywhere in your CSS and yours wins instead.

:root {
  --ui-border: #d4d4d8;        /* zinc-300 */
  --ui-border-subtle: #e4e4e7; /* zinc-200 */
}

html.dark {
  --ui-border: #3f3f46;        /* zinc-700 */
  --ui-border-subtle: #27272a; /* zinc-800 */
}

--ui-border-subtle is the quieter one, used for dividers and the inner edges of cards. Neither needs to be defined for components to render - this is an override, not a requirement.

Troubleshooting