Navigation
StepperPro
Shows progress through an ordered flow, horizontal or vertical, with complete, current, upcoming and error states and clickable completed steps.
npx prodular-ui add stepperPart of Prodular UI Pro. Preview and read the docs freely, install with a license. See pricing
Horizontal
A setup wizard. Completed steps are buttons, so people can go back. It stacks on small screens.
- 2, current stepBank accountFor payouts
- 3Tax detailsVAT or EIN
- 4ReviewConfirm and submit
Connect the account Ledgerline pays out to every Friday.
"use client"
import * as React from "react"
import { Button } from "@/components/ui/button"import { Stepper, StepperDescription, StepperIndicator, StepperItem, StepperSeparator, StepperText, StepperTitle, StepperTrigger,} from "@/components/ui/stepper"
const steps = [ { title: "Company", description: "Legal name and address" }, { title: "Bank account", description: "For payouts" }, { title: "Tax details", description: "VAT or EIN" }, { title: "Review", description: "Confirm and submit" },]
const content = [ "Enter the legal entity that will appear on invoices.", "Connect the account Ledgerline pays out to every Friday.", "Add a tax id so invoices include the right tax lines.", "Check everything once more. You can change it later in Settings.",]
export default function StepperHorizontal() { const [step, setStep] = React.useState(1) const done = step === steps.length return ( <div className="flex w-full max-w-3xl flex-col gap-6"> <Stepper value={step} onValueChange={setStep} aria-label="Payout setup"> {steps.map((s, i) => ( <StepperItem key={s.title} step={i}> <StepperTrigger> <StepperIndicator /> <StepperText> <StepperTitle>{s.title}</StepperTitle> <StepperDescription>{s.description}</StepperDescription> </StepperText> </StepperTrigger> {i < steps.length - 1 && <StepperSeparator />} </StepperItem> ))} </Stepper> <div className="flex flex-col gap-4 border-t pt-5 sm:flex-row sm:items-center sm:justify-between"> <p className="text-sm text-muted-foreground"> {done ? "Payout setup is complete. Your first payout goes out Friday." : content[step]} </p> <div className="flex shrink-0 gap-2"> <Button variant="outline" disabled={step === 0} onClick={() => setStep((s) => Math.max(0, s - 1))}> Back </Button> {done ? ( <Button variant="outline" onClick={() => setStep(0)}> Start over </Button> ) : ( <Button onClick={() => setStep((s) => s + 1)}>{step === steps.length - 1 ? "Submit" : "Continue"}</Button> )} </div> </div> </div> )}Vertical with an error
A checklist with descriptions. A failed step shows the error state until it is retried.
- , needs attentionVerify the webhook endpointWe could not reach https://api.northwind.io/hooks. It returned 404.
- 4Send a test invoiceIssue one invoice in test mode and watch it settle.
- 5Go liveSwitch the key to live mode.
"use client"
import * as React from "react"
import { Button } from "@/components/ui/button"import { Stepper, StepperDescription, StepperIndicator, StepperItem, StepperSeparator, StepperText, StepperTitle, StepperTrigger,} from "@/components/ui/stepper"
const steps = [ { title: "Install the CLI", description: "npm i -g @ledgerline/cli, then ledgerline login." }, { title: "Create an API key", description: "Restricted to invoices:write for this environment." }, { title: "Verify the webhook endpoint", description: "We could not reach https://api.northwind.io/hooks. It returned 404." }, { title: "Send a test invoice", description: "Issue one invoice in test mode and watch it settle." }, { title: "Go live", description: "Switch the key to live mode." },]
export default function StepperVertical() { const [step, setStep] = React.useState(2) const [failed, setFailed] = React.useState(true) return ( <div className="flex w-full max-w-md flex-col gap-6"> <Stepper orientation="vertical" value={step} onValueChange={setStep} aria-label="Integration checklist"> {steps.map((s, i) => ( <StepperItem key={s.title} step={i} status={failed && i === 2 && step === 2 ? "error" : undefined}> <StepperTrigger> <StepperIndicator /> <StepperText> <StepperTitle>{s.title}</StepperTitle> <StepperDescription> {i === 2 && !failed ? "Endpoint verified. Signing secret saved." : s.description} </StepperDescription> </StepperText> </StepperTrigger> {i < steps.length - 1 && <StepperSeparator />} </StepperItem> ))} </Stepper> <div className="flex gap-2 pl-9"> {failed && step === 2 ? ( <Button size="sm" onClick={() => setFailed(false)}> Retry verification </Button> ) : ( <Button size="sm" disabled={step >= steps.length} onClick={() => setStep((s) => s + 1)}> Mark step done </Button> )} <Button size="sm" variant="ghost" onClick={() => { setStep(2) setFailed(true) }} > Reset </Button> </div> </div> )}Anatomy
<Stepper value={step} onValueChange={setStep} aria-label="Payout setup"> <StepperItem step={0}> <StepperTrigger> <StepperIndicator /> <StepperText> <StepperTitle>Company</StepperTitle> <StepperDescription>Legal name and address</StepperDescription> </StepperText> </StepperTrigger> <StepperSeparator /> </StepperItem></Stepper>Guidance
Use it when
- Flows of three to six steps that must happen in order: onboarding, payout setup, an integration checklist.
- Vertical when steps need a description or the flow lives in a sidebar.
Avoid
- Steps that can be done in any order. Use a checklist or tabs.
- More than six steps. Group them into stages.
- Letting people jump ahead to upcoming steps. Only completed steps are clickable.
Rules for AI agents
Published in llms-full.txt and the registry, so coding agents follow them when they build with this component.
- Pass value as the zero-based index of the current step and give every StepperItem its step index.
- Pass onValueChange to make completed steps clickable. Without it the stepper is display only.
- Render StepperSeparator in every item except the last.
- Set status="error" on the step that failed and say why in StepperDescription. Do not use color alone.
- Give the Stepper an aria-label that names the flow. The current item gets aria-current="step" automatically.
- Keep titles to one or two words and descriptions to one short line.
API
Stepper
| Prop | Type | Default | Description |
|---|---|---|---|
| value | number | Zero-based index of the current step. | |
| onValueChange | (step: number) => void | Makes completed steps clickable. | |
| orientation | "horizontal" | "vertical" | "horizontal" | Layout. Horizontal stacks below the sm breakpoint. |
StepperItem
| Prop | Type | Default | Description |
|---|---|---|---|
| step | number | Index of this step. | |
| status | "complete" | "current" | "upcoming" | "error" | Overrides the status derived from value. |
StepperIndicator
| Prop | Type | Default | Description |
|---|---|---|---|
| children | ReactNode | Replaces the number or icon inside the circle. |