Skip to main content

Stepper

A stepped navigation component used to guide users through a sequential multi-stage process. Use when each step must be completed in order. Don't use for more than 7 steps.

OverviewStyleAccessibility

Description

Anatomy

PartRequired?Notes
Step indicator (circle/icon) Required A numbered circle for upcoming and current steps; a checkmark icon for completed steps. Communicates state at a glance.
Step label Required Short text label naming the step (e.g. 'Contact details', 'Review'). Must be concise — no more than 3 words.
Connector line Required Horizontal or vertical line linking adjacent step indicators. Fills with the interactive colour as steps are completed.
Step subtitle Optional A secondary line of text below the label providing brief context (e.g. 'Required fields only'). Use sparingly.
Step content area Required The region below or beside the stepper where the active step's form or content is rendered. Not part of the stepper component itself but must be clearly associated.
Navigation controls Recommended Back and Next/Submit buttons that live below the step content. Typically a Button pair; the stepper does not render these itself.

Variants

States

State Behaviour
Upcoming Step indicator is an outlined circle with a muted fill (--op-color-bg-secondary). Label text uses --op-color-text-secondary. Connector line to this step is unfilled.
Current (active) Step indicator circle uses --op-color-interactive-default fill with white numeral. Label uses --op-color-text-primary and font-weight bold. A visible focus ring (3px, --op-color-interactive-focus) is present when the indicator has keyboard focus.
Completed Step indicator shows a checkmark icon on --op-color-interactive-default background. Connector line leading to this step fills with --op-color-interactive-default. Label text uses --op-color-text-secondary.
Error Step indicator shows an alert icon on --op-color-status-error background. Label uses --op-color-status-error. Use when the user returns to a step that contains a validation error.
Disabled Step indicator and label use --op-color-text-disabled. The step is not clickable or focusable. Reserved for steps locked behind incomplete prerequisites. Avoid overuse — government users need to understand why a step is unavailable.

Usage guidelines

Do / Don't

Do

Keep step labels to 1–3 words so they remain legible at all viewport widths.

Don't

Don't use full sentences or questions as step labels (e.g. 'What are your contact details?' is too long).

Do

Save progress at each step so users can return without losing data.

Don't

Don't require users to restart the entire process if they navigate away or their session expires.

Do

Allow users to navigate back to completed steps to review or edit their answers.

Don't

Don't lock completed steps — government users frequently need to check earlier answers before submitting.

Do

Show validation errors inline within the step content, and reflect the error state on the step indicator.

Don't

Don't show a generic error at the top of the page without indicating which step contains the problem.

Do

Use the vertical variant on mobile viewports.

Don't

Don't force a 5-step horizontal stepper on a 375px screen — labels will truncate or overflow.

Layout & Spacing

Horizontal stepper:

  • Indicator diameter: 32px (compact: 24px)
  • Gap between indicator and label: --op-space-8 (8px)
  • Gap between step columns: --op-space-32 (32px) minimum
  • Connector line height: 2px; fills horizontally from left

Vertical stepper:

  • Indicator diameter: 32px (compact: 24px)
  • Gap between indicator and label: --op-space-12 (12px)
  • Row gap between steps: --op-space-24 (24px)
  • Connector line width: 2px; runs vertically between indicators

Navigation controls below step content:

  • Margin top from content: --op-space-32 (32px)
  • Back button: secondary variant, left-aligned
  • Next/Submit button: primary variant, right-aligned or left of Back on mobile

Tokens

PartTokenValue
Indicator — upcoming --op-color-bg-secondary Fill; border uses --op-color-border-default
Indicator — current --op-color-interactive-default Fill (green-400); numeral in white
Indicator — completed --op-color-interactive-default Fill; checkmark icon in white
Indicator — error --op-color-status-error Fill; alert icon in white
Indicator — disabled --op-color-bg-secondary Fill; numeral uses --op-color-text-disabled
Connector line — incomplete --op-color-border-default Unfilled connector
Connector line — complete --op-color-interactive-default Filled connector leading into a completed step
Step label — current --op-color-text-primary Bold weight via --op-font-body
Step label — upcoming / completed --op-color-text-secondary Regular weight
Step label — error --op-color-status-error Communicates error state in label
Step label — disabled --op-color-text-disabled
Focus ring --op-color-interactive-focus 3px solid, offset 2px, on indicator when focused
Step subtitle --op-color-text-secondary --op-text-xs; only visible for current and upcoming steps

Engineering notes

  • The stepper is a presentational component. Step state (upcoming, current, completed, error, disabled) is managed by the parent form or wizard controller.
  • Wrap the stepper in a <nav> element with aria-label='Progress' to give screen readers context.
  • Each step indicator should be an <ol> list item so the total step count is announced by screen readers.
  • The current step's <li> should carry aria-current='step'. Completed steps should use aria-label that includes 'completed' (e.g. 'Step 1: Details, completed').
  • Do not use anchor tags for non-navigable upcoming or disabled steps. Use <button> (disabled) or <span> for display-only indicators.
  • Connector lines are decorative — use aria-hidden='true' on the connector element.
  • For vertical layout on small screens, use a CSS custom property or a data attribute (data-orientation='vertical') to switch layout rather than a separate component.
  • Persist step data to sessionStorage or server-side on each Next action so users can recover from session interruptions — especially important in government-facing submission flows.
  • Avoid animating connector fill if prefers-reduced-motion is set. Use CSS: @media (prefers-reduced-motion: reduce) { .stepper-connector { transition: none; } }

Keyboard interaction

KeyAction
Tab Moves focus to the next interactive element. Completed step indicators (if clickable) receive focus in DOM order.
Shift+Tab Moves focus to the previous interactive element.
Enter Activates a completed step indicator (if implemented as a button) to navigate back to that step.
Space Activates a focused button-type step indicator.

Why it matters

Government digital services must meet WCAG 2.1 AA. Many users of Open Point and Social Point access services using assistive technology or keyboard-only navigation. A stepper that relies solely on visual position or colour to communicate progress will fail these users. Screen reader users need to hear which step they are on, how many steps there are in total, and whether previous steps are complete or have errors.

Focus

When the user advances to the next step (via the Next button), focus should move to either:

  • The heading of the new step's content area, or
  • The first interactive element within the new step content. Do NOT move focus to the step indicator itself on step transition — the indicator is not the interactive destination. Completed step indicators that allow back-navigation must be focusable buttons with a visible 3px focus ring using --op-color-interactive-focus.

ARIA

Role or attributeWhen to useExample
nav (landmark) Wrap the entire stepper in <nav aria-label='Progress'> so screen reader users can locate and skip the progress indicator. <nav aria-label="Progress"><ol class="stepper">...</ol></nav>
aria-current="step" Apply to the <li> or indicator element representing the active step. <li aria-current="step">Step 2: Stakeholders</li>
aria-label (on completed steps) Override the visible label to include completion status so screen readers announce it. <li aria-label="Step 1: Details, completed">
aria-label (on error steps) Include error status in the accessible label. <li aria-label="Step 3: Review, contains errors">
aria-disabled="true" Apply to disabled step indicators rendered as buttons. <button aria-disabled="true">Step 4: Submit</button>
aria-hidden="true" Apply to decorative connector lines and icon SVGs inside indicators. <span class="connector" aria-hidden="true"></span>

Contrast

  • Indicator fill (--op-color-interactive-default, green-400) with white numeral/icon must meet 4.5:1 for normal text or 3:1 for large/bold icons. Verify at implementation.
  • --op-color-status-error fill with white icon must meet 3:1 minimum for the icon size used.
  • Step labels (--op-color-text-secondary on --op-color-bg-primary) must meet 4.5:1.
  • Disabled labels (--op-color-text-disabled) are exempt from contrast requirements per WCAG 1.4.3 but should remain legible enough to identify the step name.
  • Focus ring: --op-color-interactive-focus at 3px must meet WCAG 2.4.11 (focus appearance, AA) — verify against the background behind the indicator.

Touch targets

Each clickable step indicator must be at least 44x44px. The default 32px indicator diameter is below this threshold — implement a transparent hit-area padding around the indicator to meet the minimum. In compact variant, the 24px indicator requires even more padding.

Things to avoid

Was this page helpful?

Updated 5 October 2026