Stepper
A linear progress indicator for a flow the user moves through in a fixed order — phone-number verification’s enter/verify-old/verify-new legs, an onboarding wizard. Unlike Tabs, steps are not clickable: `activeStep` is the only state.
import Stepper from '@/components/ui/Stepper';Source: src/components/ui/Stepper.tsx
Examples
Horizontal
- Add number
- Verify current number
- Verify new number
Vertical
- Add number
- Verify current number
- Verify new number
Props
<Stepper> props
| Prop | Type | Default | Description |
|---|---|---|---|
stepsrequired | string[] | — | Step labels, in order. |
activeSteprequired | number | — | 0-indexed: the step the user is currently on. Earlier steps show done, later ones upcoming. |
orientation | 'horizontal' | 'vertical' | 'horizontal' | — |
className | string | '' | — |
activeContent | ReactNode | — | Vertical only: rendered indented under the active step's label, with the connector stretching past it down to the next step — e.g. the form for whichever leg of a multi-step flow the user is currently on. Ignored in horizontal orientation. |
Accessibility
- The current step carries `aria-current="step"`; done steps swap their number for a checkmark, marked `aria-hidden` since the list order already conveys position to a screen reader.
Usage
Do
- Derive `activeStep` from the flow’s own state (PhoneForm’s `challenge.sentTo`) rather than a counter the component maintains itself — the step the user is on should never disagree with what the form is actually doing.
- Keep step labels short enough to fit under a single circle in the horizontal layout; a wrapping label still centers, but two short words read faster than a sentence.
Don’t
- Don’t make steps clickable — this reports progress through a flow the API drives, it doesn’t let the user jump ahead of a challenge they haven’t completed.