Skip to content
ComponentsStagesCard

StagesCard

When to use

Reach for StagesCard when a single operation expands into a known sequence of discrete sub-operations, and you want the user to see each one tick over rather than wait behind an opaque spinner. The canonical case is workspace provisioning during the new-entity onboarding flow — five stages (provision container, create vault, init audit log, wire assistant, add to portfolio) that complete in ~5 seconds.

Don't reach for StagesCard for an indeterminate progress bar — use Progress. Don't use it for a hierarchical operation tree — that's ThinkingTree.

Anatomy

  • Header. Optional eyebrow, required title, optional status pill in the top-right.
  • Stages list. One row per stage. Each row has a 14px circular dot (pending = empty ring; running = pulsing ring; done = filled green dot) + label + monospaced meta column on the right (revealed only when status === done, carrying the reference id; shows when running; blank when pending).

The list is rendered as an <ol> with aria-live="polite" so screen-reader users hear the transitions.

Props

PropTypeDefaultDescription
eyebrowReact.ReactNodeEyebrow above the headline.
titlerequiredReact.ReactNodeHeadline copy.
statusPillReact.ReactNodeStatus pill or any other element rendered top-right.
stagesrequiredStage[]
classNamestring
styleReact.CSSProperties

States

States live at the stage level, not the card level. Each stage moves through pending → running → done. The card itself is always rendered the same — the animation comes from per-stage status changes.

Tokens consumed

No tokens match. No tokens match.

Done dots read --status-green filled with --status-green-13 halo. Running dots read the same green ring with the halo. Pending dots read --ink-12. Stage labels read --fg (running/done) or --fg-soft (pending). The meta column reads --fg-soft in Geist Mono.

Accessibility

  • Keyboard interactions. None — passive surface.
  • ARIA roles and properties. <ol aria-live="polite"> for the stages list. Each <li> carries data-status for testing + downstream selectors.
  • Focus order. Not focusable.
  • Screen-reader expectations. Each stage transition is announced as the underlying data updates.
  • Reduced motion. The running-state pulse should be disabled under @media (prefers-reduced-motion) — wire this at the consumer's stylesheet level until it lands in the canonical motion-recipes.
  • Forced colors. Dots map to system colors as described above.

On this page