Zetta v1.6

Components · Wayfinding

Stepper

Ordered multi-step progress indicator for sequential flows. Split from zetta-navigation-v1_4.md (removed in v1.5) in v1.4.

Preview

Build with the skill

No package to install — hand this to your AI to generate or migrate the component in your stack.

Prompt for your AI
Apply the Zetta "Stepper" component to this project using the zetta-design-md skill.

WHEN TO USE
- Migrating or fixing existing code (the common case): audit the current implementation against the `stepper` spec and CORRECT every deviation — replace off-spec values, don't only add new ones.
- New component: build it to the `stepper` spec in this project's stack.

AUDIT & FIX (when the component already exists)
Compare it to the skill's spec and fix, don't just append: hardcoded colors/hex, off-scale radius, wrong fonts, dark/navy fills, shadows used in place of borders (or missing borders), brand lime used as a CTA or interaction (must be primary indigo), and any missing or wrong hover / focus / active / disabled / invalid state or missing 2px focus ring. Replace each with the correct Zetta token.

ALWAYS
- Pull the authoritative spec and tokens from the skill — never guess or hardcode values.
- Use this project's own component conventions and framework idioms.
- Honor the Zetta guardrails (brand = identity only, primary = interaction, shadows for overlays) and verify in Light, Dark, and Accessibility.

Anatomy & rules

  ①  ──────────  ②  ──────────  ③  ──────────  ④
Account        Payment        Review          Done
 ↑ active       ↑ upcoming     ↑ upcoming      ↑ upcoming
(primary)      (surface-      (surface-       (surface-
               secondary)     secondary)      secondary)

Completed step:
  ✓  ══════════  ②
Details          Payment
(primary-bg      (upcoming)
 + check icon)
State Indicator fill Indicator border Icon Label
Upcoming {colors.surface-secondary} {colors.hairline} Step number {colors.muted} / 400
Active {colors.primary} {colors.primary} Step number {colors.ink} / 500
Completed {colors.primary-bg} {colors.primary} check_circle filled {colors.muted} / 400
Error {colors.danger-bg} {colors.danger} error icon {colors.danger} / 400
Disabled {colors.disabled-bg} {colors.disabled-border} Step number {colors.disabled-text}

Connector: {colors.hairline} when step to the left is upcoming or active. {colors.primary} when step to the left is completed.

When to use

  • Multi-step forms or wizards where steps must be completed in order.
  • When showing progress through a linear flow is meaningful to the user.

When not to use

  • If steps can be completed in any order — use standard Tabs.
  • More than 7 steps — break into sections.
  • Single-step flows — just show the form.

Do

  • Mark all completed steps with a check icon — not just the most recently completed.
  • Allow users to navigate back to completed steps if the flow permits (set navigable={true}).
  • Validate the current step before advancing.

Don't

  • Don't allow users to skip ahead to incomplete steps.
  • Don't use more than 7 steps in one stepper.
  • Don't truncate step labels.
  • Step labels: 1–3 words. Match the action: "Account details", "Payment", "Confirm order".
  • Use noun phrases or short verb phrases — not full sentences.
  • Completed step aria-label: "Step 1 of 4: Account details — completed."
  • Active step aria-label: "Step 2 of 4: Payment — current step."
  • Error step aria-label: "Step 3 of 4: Review — error, please correct before continuing."

Keyboard

Key Behavior
Tab Move focus through step indicators
Enter / Space Navigate to step (if navigable and step is completed)

Accessibility

  • role="list" on stepper-tabs-list, role="listitem" on each step trigger.
  • Each step indicator: aria-label="Step N of M: [label] — [state]".
  • Active step: aria-current="step".
  • Connector lines: aria-hidden="true" — decorative.
  • Focus ring: 2px solid {colors.border-focus} at 2px offset on each trigger.

Spec

Values and token references resolved straight from the Zetta spec.

stepper-tabs-list
display
flex
flexDirection
row
alignItems
center
gap
0
stepper-tabs-connector
flex
1
height
1px
backgroundColor
{colors.hairline}
stepper-tabs-connector-completed
backgroundColor
{colors.primary}
stepper-tabs-trigger
display
flex
flexDirection
column
alignItems
center
gap
{spacing.xs}
cursor
pointer
position
relative
stepper-tabs-trigger-focus
outline
2px solid {colors.border-focus}
outlineOffset
2px
borderRadius
{rounded.base}
stepper-step-indicator
width
28px
height
28px
borderRadius
{rounded.full}
backgroundColor
{colors.surface-secondary}
borderColor
{colors.hairline}
borderWidth
1px
textColor
{colors.muted}
fontFamily
Geist
fontSize
13px
fontWeight
500
display
flex
alignItems
center
justifyContent
center
stepper-step-indicator-active
backgroundColor
{colors.primary}
borderColor
{colors.primary}
textColor
{colors.primary-text}
stepper-step-indicator-completed
backgroundColor
{colors.primary-bg}
borderColor
{colors.primary}
textColor
{colors.primary}
stepper-step-indicator-error
backgroundColor
{colors.danger-bg}
borderColor
{colors.danger}
textColor
{colors.danger}
stepper-step-label
textColor
{colors.muted}
fontFamily
Geist
fontSize
12px
fontWeight
400
stepper-step-label-active
textColor
{colors.ink}
fontWeight
500
stepper-step-label-completed
textColor
{colors.muted}