Progress stepper
Step indicator for multi-step flows. Two variants — labeled vertical steps and compact horizontal dots.
ProgressStepper shows where the user is in a multi-step flow. One component, two layouts: steps (labeled, vertical or horizontal with descriptions) and dots (compact horizontal indicator). Both share the same activeStep, linear, and onStepClick model.
The dots variant replaced the standalone ProgressDots component per ADR-004 §3 — same shape, same logic, different layout = one component with a variant prop, not two.
Note: this is not the same as Stepper — that's a numeric +/− input.
Use it for
- Checkout / signup / setup wizard step indicators
- Multi-page form progress
- Onboarding flow markers
- Any sequential flow where the user benefits from seeing position + total steps
For boolean done/in-progress on a single task, use ProgressBar. For numeric input, use Stepper.
Import
import { ProgressStepper } from '@brikdesigns/bds';Variants
Steps (default, labeled)
<ProgressStepper
steps={[
{ label: 'Account' },
{ label: 'Profile' },
{ label: 'Review' },
]}
activeStep={1}
/>Steps with descriptions
<ProgressStepper
steps={[
{ label: 'Details', description: 'Enter your information' },
{ label: 'Payment', description: 'Add billing details' },
{ label: 'Confirm', description: 'Review and submit' },
]}
activeStep={0}
onStepClick={(step) => setStep(step)}
/>Dots variant — compact horizontal
The active dot stretches wider; completed dots are dimmed; upcoming dots are muted. No label text — pair with a page heading or step counter.
<ProgressStepper
variant="dots"
count={5}
activeStep={2}
onStepClick={(step) => setStep(step)}
/>Linear mode
Restrict navigation to sequential steps — clicking a future step beyond activeStep + 1 is blocked. Use for flows where steps depend on completion of prior ones.
<ProgressStepper
steps={steps}
activeStep={1}
linear
onStepClick={(step) => setStep(step)}
/>Sizes
sm for constrained layouts, md (default) otherwise.
<ProgressStepper steps={steps} activeStep={0} size="sm" />When not to use
Don't use ProgressStepper for measurable progress within a single task. That's ProgressBar. ProgressStepper is for between discrete steps; ProgressBar is for within a single step.
- Don't use Steps with >5 entries. A 7-step labeled flow is unscannable — switch to
dotsand lean on the page heading for context. - Don't use Dots for unfamiliar flows. Without labels, dots assume the user already knows what each step is about. Use Steps for first-time-user flows.
Accessibility
- Renders an
<ol>witharia-labeldescribing the flow. - Active step carries
aria-current="step". onStepClickmakes each step a real<button>— keyboard navigation, focus ring all work.linearmode disables future steps viaaria-disabledso assistive tech announces the constraint.
API
| Prop | Type | Default |
|---|---|---|
variant | 'steps' | 'dots' | 'steps' |
activeStep | number (0-indexed) | — |
steps | Array<{ label: string; description?: string }> (steps variant) | — |
count | number (dots variant) | — |
linear | boolean | false |
onStepClick | (step: number) => void | — |
size | 'sm' | 'md' | 'md' |
The steps and count props are mutually exclusive — variant="steps" requires steps, variant="dots" requires count.
Related
- ProgressBar — within-step progress
- Stepper — different component (numeric input)
- Pagination — page navigation, not flow progress
- Storybook playground