busy-office-ui
Menu

Stepper

Wizard progress for multi-step documents. State has two channels, always: the marker glyph (aria-hidden) AND visually-hidden state text / aria-current. The stepper is its own named container — labels collapse to screen-reader-only when it narrows; markers stay. Not for switching between independent sections — a stepper asserts order: earlier steps are complete, later ones are not yet reachable, and the numbers promise a sequence. Sections a reader may visit in any order are tabs; if the "steps" can be done in any order, the numbers are a lie and readers will still assume they cannot skip ahead.

  1. Completed: Header
  2. Completed: Line items
  3. 3Approvers
  4. 4Not started: Review

Narrow container (labels collapse, names retained)

  1. Completed: Header
  2. 2Line items
  3. 3Not started: Review

Markup

<ol class="bo-stepper" role="list">
  <li class="bo-stepper__step" data-state="done">
    <span class="bo-stepper__marker" aria-hidden="true">✓</span>
    <span class="bo-stepper__label"><span class="bo-visually-hidden">Completed: </span>Header</span>
  </li>
  <li class="bo-stepper__step" aria-current="step">
    <span class="bo-stepper__marker">2</span>
    <span class="bo-stepper__label">Line items</span>
  </li>
  <li class="bo-stepper__step">
    <span class="bo-stepper__marker">3</span>
    <span class="bo-stepper__label"><span class="bo-visually-hidden">Not started: </span>Review</span>
  </li>
</ol>

Quick reference generated

ClassRole
.bo-stepper block (root)
.bo-stepper__label part: label
.bo-stepper__marker part: marker
.bo-stepper__step part: step

State attributes: data-statearia-current

API generated from CSS

Blocks bo-stepper
Parts bo-stepper__labelbo-stepper__markerbo-stepper__step
data-* hooks data-state="done"
ARIA styled aria-current
Component tokens --bo-stepper-marker-bg--bo-stepper-marker-fg
Named containers bo-stepper
JS required None to display progress. initWizard() is opt-in and only for the case where the stepper drives a multi-step flow: it shows one [data-wizard-panel] at a time and keeps this stepper in sync, setting data-state=done behind the current step and aria-current=step on it.
  • aria-current="step" marks the current step; do not combine with data-state="done" (current wins by source order but the combination is out of contract).
  • Steps are inert <li> by contract — interactive (clickable) steps are not yet specified.
  • Print: markers render outlined black-on-white automatically.
Contrast — 24 AA pairs this component uses (generated, CI-gated)
TextonLightDark
text-primary bg-surface 17.74 16.15
text-primary bg-canvas 16.98 18.08
text-secondary bg-surface 10.31 11.46
text-secondary bg-muted 9.37 9.75
text-muted bg-surface 7.56 6.65
text-muted bg-muted 6.87 5.66
text-inverse accent-solid 5.47 5.47
text-inverse danger-solid 4.83 4.83
bg-surface text-primary 17.74 16.15
success-text success-subtle 4.79 10.17
success-text bg-surface 5.02 12.02
success-text bg-canvas 4.8 13.46
text-primary bg-hover 16.12 13.75
text-primary bg-selected 17.01 11.86
text-secondary bg-selected 9.88 8.41
text-primary bg-surface-raised 17.74 14.51
text-secondary bg-canvas 9.86 12.82
border-control bg-muted 4.39 5.66
accent bg-muted 4.97 7.72
warning-strong bg-muted 4.56 6.69
danger bg-muted 4.39 5.19
text-primary bg-muted 16.12 13.75
success-text bg-muted 4.56 10.23
danger-text bg-muted 5.88 7.57

Maturity generated

Introduced
v0.1.0
CSS floor
Chrome/Edge 105 · Firefox 110 · Safari 16
Alignment scored
2026-08-23
Assistive-tech evidence
None recorded

Pin this component's first release with npm i @busy-office/ui@0.1.0. The floor is derived from this component's stylesheet alone — set by @container — so it sits at or below the whole framework's Chrome/Edge 119 · Firefox 129 · Safari 17.5. No assistive-technology runtime result is recorded for any component: it needs a human listening to VoiceOver and NVDA on owner hardware; no gate in this repo can simulate announcement behaviour. What automation covers instead is test:axe across every page at 1440 and 390, and check:forced-colors — see accessibility.

Design-system alignment generated

100% (15/15) — how closely this component follows the design language. Each rule is scored 0-3 against a checkable citation; rules that don't apply leave the denominator. Scored 2026-08-23.

Rule Score Evidence
Typography 3 / 3 marker on --bo-font-size-sm with tabular-nums, label on --bo-density-font-size; no raw font-size
Colour 3 / 3 raw hex appears ONLY inside @media print, where theme tokens would be wrong on paper; state is two-channel via a real ✓ in the marker markup
Spacing 3 / 3 the 1.75rem marker and 2px connector both carry their reason (94.6b)
Interaction n/a an <ol> reporting position; the wizard’s controls live elsewhere
Content 3 / 3 opener carries the wrong-choice clause: "Not for switching between independent sections" — a stepper asserts order and its numbers promise a sequence; free-order sections are tabs. Blind re-scored 2026-08-23 (Polish round 14); consistent with the ApiTable note that steps are inert li elements, so section-switching is doubly wrong.
Fit 3 / 3 discrete named steps in a multi-step document; container-queried for narrow shells
↑↓ move Enter open Esc close