labsUI

Stepper

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.

npx @kznlabs/labsui add stepper
  1. 1
  2. 2
  3. 3

Step 1 of 3: Server

ServerWhere the bot will live.

17–20 digits. Try one starting with 000.

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>  );}

<Stepper>

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.

PropTypeDefault
steps*

Steps in order: value, title and an optional description for the header.

StepInfo[]—
defaultValue

Step shown at first render (uncontrolled).

string—
onValueChange

Called with the new step's value.

(value: string) => void—
value

Current step's value. Controlled with onValueChange, or start at defaultValue.

string—

Also accepts every <form> prop.

<StepperList>

Progress header. Finished steps are links back; the connector fills on a spring.

Also accepts every <ol> prop (none of its own).

<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.

PropTypeDefault
children*

The step's fields.

ReactNode—
value*

Matches a step in steps.

string—
onNext

Runs on Continue after the native checks; return false to stay.

Guard—

<StepperFooter>

Back and Continue; the last step's button submits. Continue shows a spinner while onNext runs.

  • backLabeldefault "Back"
    ReactNode

    Back button text.

  • nextLabeldefault "Continue"
    ReactNode

    Continue button text.

  • submitLabeldefault "Submit"
    ReactNode

    Submit button text on the last step.

PropTypeDefault
backLabel

Back button text.

ReactNode"Back"
nextLabel

Continue button text.

ReactNode"Continue"
submitLabel

Submit button text on the last step.

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

* required. Every component also takes className.