# Stepper

- Page: <https://kznlabs.github.io/labsUI/components/stepper>

## Stepper (`stepper`, component)

Multi-step form (questionnaire, checkout, setup wizard). Steps stay mounted so values survive Back and submit together; Continue checks only the current step's native constraints, plus an optional async onNext guard with a spinner. Progress header with springing connectors; works with onSubmit or a Server Action.

- Install: `npx @kznlabs/labsui add stepper`
- Docs: <https://kznlabs.github.io/labsUI/components/stepper>
- Brings: button, button-variants, use-controllable-state, utils
- npm: clsx@^2.1.1, lucide-react@1.63.0, motion@14.7.1, tailwind-merge@^3.7.0

### API

- `<Stepper>` (+ <form> props): Multi-step form. Every step stays mounted (hidden), so values survive Back and submit
together; Continue checks only the current step's native constraints, and the last step
submits the form (`onSubmit`, or a Server Action through `action`).
  - `steps: StepInfo[]`: Steps in order: `value`, `title` and an optional `description` for the header.
  - `defaultValue?: string`: Step shown at first render (uncontrolled).
  - `onValueChange?: (value: string) => void`: Called with the new step's `value`.
  - `value?: string`: Current step's `value`. Controlled with `onValueChange`, or start at `defaultValue`.
- `<StepperList>` (+ <ol> props): Progress header. Finished steps are links back; the connector fills on a spring.
- `<StepperStep>`: One step's fields. Hidden, not unmounted, while inactive. `onNext` runs after its native
constraints pass; return false (or resolve false) to stay, e.g. after a server check.
  - `children: ReactNode`: The step's fields.
  - `value: string`: Matches a step in `steps`.
  - `onNext?: Guard`: Runs on Continue after the native checks; return false to stay.
- `<StepperFooter>`: Back and Continue; the last step's button submits. Continue shows a spinner while `onNext` runs.
  - `backLabel?: ReactNode` = `"Back"`: Back button text.
  - `nextLabel?: ReactNode` = `"Continue"`: Continue button text.
  - `submitLabel?: ReactNode` = `"Submit"`: Submit button text on the last step.

- `type StepInfo = { value: string; title: string; description?: string }`
- `type Guard = () => boolean | undefined | Promise<boolean | undefined>`

### Usage

```tsx
<Stepper steps={[{ value: "server", title: "Server" }, { value: "bot", title: "Bot" }]} action={createBot}><StepperList /><StepperStep value="server"><Input name="serverId" required /></StepperStep><StepperStep value="bot">…</StepperStep><StepperFooter submitLabel="Create bot" /></Stepper>
```

### Example: setup-wizard.tsx

```tsx
import { Field } from "@/components/ui/field";
import { Input } from "@/components/ui/input";
import { Stepper, StepperFooter, StepperList, StepperStep } from "@/components/ui/stepper";
import { createBot } from "./actions"; // "use server"

const steps = [
  { value: "server", title: "Server", description: "Where the bot will live." },
  { value: "bot", title: "Bot", description: "How members will see it." },
];

// Server page: steps are plain data and the form posts to a Server Action.
export default function SetupPage() {
  return (
    <Stepper steps={steps} action={createBot}>
      <StepperList />
      <StepperStep value="server">
        <Field label="Server ID" required>
          <Input name="serverId" pattern="[0-9]{17,20}" />
        </Field>
      </StepperStep>
      <StepperStep value="bot">
        <Field label="Display name" required>
          <Input name="botName" maxLength={32} />
        </Field>
      </StepperStep>
      <StepperFooter submitLabel="Create bot" />
    </Stepper>
  );
}
```
