Steps
Shows the steps of a flow.
Orientation
- , doneBuild1m 12s
- , doneEvaluate200 tickets
- 3, currentReviewWaiting on you
- 4ShipTo production
horizontaldefault
- , doneBuild1m 12s
- , doneEvaluate200 tickets
- 3, currentReviewWaiting on you
- 4ShipTo production
vertical
Sizes
- , doneBuild1m 12s
- , doneEvaluate200 tickets
- 3, currentReviewWaiting on you
- 4ShipTo production
sm
- , doneBuild1m 12s
- , doneEvaluate200 tickets
- 3, currentReviewWaiting on you
- 4ShipTo production
defaultdefault
States
- , doneBuild
done
- 2, currentEvaluate
current
- 2Review
upcoming
- , runningEvaluate
pending
- MigrateFailed
error
Usage
When to use it
- Use
- A flow has two to six steps in a fixed order and the person needs to see where they are: a setup, an import.
- Use
- Work runs through stages and each stage has a state: a deploy, an agent's plan.
- Not for
- The panels can be read in any order. Use Tabs.
- Not for
- Only the share done matters, with no named steps. Use Progress.
- Not for
- The events have times and a log of what happened. Use Item.
Rules
8 rules
- Must
- Give Steps an aria-label naming the flow: "Deploy", "Connect a data source". Because the list is read as "list, 4 items" with no name, so a screen reader cannot tell a deploy's stages from a setup.
- Must
- Number each Step from 1 in the order it renders, and pass the current one as value. Because done, current, upcoming and how far the track fills are all worked out from step against value, so a gap or a repeat marks the wrong steps done.
- Must
- Set state="pending" on a step while it runs and state="error" when it failed; never colour a title or a marker by hand. Because the state draws the arc or the coral cross and says "running" or "Failed", so a hand-set colour is a status nobody hears and a dot nobody can name.
- Should
- Put a StepSeparator in every Step, after its StepTrigger; the last step draws none. Because the track is what joins the markers into one flow, and its gradient fill up to the current step is the progress at a glance.
- Never
- Restyle a marker with glass, a hue or a status dot, or set the done gradient on any other state. Because the small glaze means done and nothing else on the row, so a glazed current marker reads as finished, and a green or dotted one as a status badge.
- Should
- Pass onValueChange only when the person can go back to a step, and leave linear on unless the steps are independent. Because a step that looks like a button but does nothing is a dead control, and a later step picked out of order skips the ones it needs.
- Should
- Title each step with a verb or a noun of one or two words, and keep the detail to one line of StepDescription. Because horizontal steps share the width and both lines truncate, so a long title loses its end.
- Should
- Use size="sm" inside a card, a panel header or a dialog, and the default on a page of its own. Because the 16px marker and 12px label sit with the 26px small controls around them; the default 20px marker beside them looks loud.
State order
5 states, highest first
- 1
- error
- 2
- pending
- 3
- done
- 4
- current
- 5
- upcoming
Accessibility
7 checks
- Steps is an ordered list, so a screen reader reads the order and the count; name it with aria-label.
- The current step carries aria-current="step".
- Each marker says its state as hidden text (done, current, running); error says "Failed" as visible text beside the label, so no state is told by shape or colour alone.
- With onValueChange each step is a button with its label as its name; steps past the current one are disabled when linear.
- The white check on the small glaze is about 6:1 at the glyph's top and 9.5:1 at its middle (4.8:1 only at the marker's top edge, where no glyph sits); in dark the ink check on the light glaze is 9:1 or better.
- The current numeral is text-1 on paper (11.9:1). The upcoming numeral is text-3 (3.3:1), a mark and not the step's name: the label beside it is text-2 at 5.5:1. The error word is the failure text at 5.9:1.
- The track is decoration (aria-hidden); the fill slides on --dur-overlay and jumps under reduced motion.
Keyboard
2 keys
- Tab
- With onValueChange, moves through the steps that can be picked.
- Enter, Space
- Goes back to the focused step.
Edge cases
8 edge cases
- Narrow container
- Horizontal labels and descriptions truncate; under 480px use orientation="vertical".
- More than six steps
- Group them into stages; a row of seven markers is too dense to read.
- A step fails
- state="error" on it, and the steps after it stay upcoming until the person retries; its track stays empty.
- A step is running
- state="pending" turns the arc in its marker; under reduced motion the arc stands still.
- Value jumps several steps
- Every track between fills at once over --dur-overlay.
- Every step done
- Pass value one past the last step, so every marker is a check, every track full and none current.
- Right to left
- The steps run right to left and the fill grows from the right.
- Dark theme
- The small glaze turns light with an ink check, and the track fill follows it.
API
9 props
Steps valuenumberdefaultrequiredSteps onValueChange(step: number) => voidSteps orientation'horizontal' | 'vertical'default'horizontal'Steps size'sm' | 'default'default'default'Steps linearbooleandefaulttrueStep step, state, disablednumber, 'done' | 'current' | 'upcoming' | 'pending' | 'error', booleandefaultstate from valueStepIndicator childrenReactNodedefaultby stateStepTitle errorTextReactNodedefault'Failed'StepTrigger, StepText, StepDescription, StepSeparatorparts
Tokens
22 tokens
--glaze-sm-top- #6b6b6b
--glaze-sm-mid- #3d3d3d
--glaze-sm-bottom- #232323
--glaze-sm-text- rgb(255 255 255 / 0.92)
--paper- #ffffff
--field- #efefef
--ink- #050505
--line- rgb(5 5 5 / 0.10)
--text-1- rgb(5 5 5 / 0.80)
--text-2- rgb(5 5 5 / 0.60)
--text-3- rgb(5 5 5 / 0.45)
--fail- #e35e49
--fail-tint- #fbe9e5
--fail-text- #b23c29
--radius-pill- 999px
--type-label- 500 13px/1.35 var(--font-sans)
--type-label-sm- 500 12px/1.35 var(--font-sans)
--type-caption- 400 12px/1.35 var(--font-sans)
--dur-overlay- 200ms
--dur-state- 160ms
--ease-out- cubic-bezier(0.2, 0.8, 0.2, 1)
--dur-spin- 800ms