Menu


Stepper


Where the reader is in a form or task of three or more ordered steps: each step's mark, name and status in words, joined by a line; or "Step 2 of 4" with the step's name and a slim track.

Customize the preview


Choices
Show
View
  1. Your details, completed.Done
  2. Delivery, current step.In progress
  3. PaymentNot started
  4. Review, unavailable.After payment

Step 2 of 4

Delivery

Options


Stepper options
ChoiceValuesDefaultWhat it does
layoutsmbk-stepper--layout-<value>horizontalverticalsummaryhorizontal
Horizontal lists the steps in a row and gives the summary instead where the layout is narrow. Vertical lists them one under another. Summary gives "Step 2 of 4", the step's name and a slim track at any width.

Partssmbk-stepper__listsmbk-stepper__itemsmbk-stepper__stepsmbk-stepper__marker-rowsmbk-stepper__markersmbk-stepper__numbersmbk-stepper__iconsmbk-stepper__connectorsmbk-stepper__textsmbk-stepper__labelsmbk-stepper__statussmbk-stepper__hiddensmbk-stepper__summarysmbk-stepper__summary-textsmbk-stepper__countsmbk-stepper__step-namesmbk-stepper__track

Examples


Usage

Four steps of a checkout: the first done, and a link back to it, the second current, the third not started and the last not open yet.

  1. Your details, completed.Done
  2. Delivery, current step.In progress
  3. PaymentNot started
  4. Review, unavailable.After payment

Step 2 of 4

Delivery

Vertical

One step under another, each name beside its mark, for a side column or a long list of steps.

  1. Your details, completed.Done
  2. Delivery, current step.In progress
  3. PaymentNot started
  4. Review, unavailable.After payment

Summary

"Step 2 of 4", the current step's name and a slim track, for a narrow space.

Step 2 of 4

Delivery

Every status

Done, an error that says what is wrong, current, not started, and unavailable with the reason. The steps with a check or a warning sign can be gone back to.

  1. Account, completed.Done
  2. Documents, error.Passport photo missing
  3. Interview, current step.In progress
  4. ContractNot started
  5. First day, unavailable.After the contract is signed

Going back to a step

Finished steps and a step with an error are links back to their pages; the pointer gives them a fill and the keyboard a focus ring.

Without status lines

Each name alone; a screen reader still hears every step's status.

  1. Write, completed.
  2. Check, completed.
  3. Schedule, current step.
  4. Publish, not started.

Step 3 of 4

Schedule

Guidelines


Purpose

Shows where the reader is in a form or task of three or more steps taken in a set order, such as a checkout or a sign-up: which steps are done, which one is current, and what comes next. It sits beside the form's own Back and Next buttons and does not replace them. It differs from the progress bar, which shows how far a single piece of work has got, and from tabs, which switch between views in any order.

When to use

  • A form split into three or more pages or sections that are filled in order.
  • A task with a fixed number of stages, such as setting up an account or importing a file.
  • To let the reader go back to a step they have finished.

When not to use

  • One page, or two steps. A heading that says what the page is for is enough.
  • Steps that can be done in any order, or whose number changes with the answers given. Use a list of tasks with their status.
  • Showing that something is loading or being worked on. Use the progress bar or the spinner.
  • Switching between views of the same thing. Use tabs.

Usage rules

Do

  • Name each step for what the reader does there, in a word or two.
  • Keep the steps to a fixed number, three or more.
  • Make a finished step a link only when going back to it really works.
  • Say what is wrong in an error step's status line.

Don't

  • Use it as the only way to move between steps.
  • Number the steps without naming them.
  • Show the stepper for a process whose steps change with the answers.
  1. Your details, completed.Done
  2. Delivery, current step.In progress
  3. PaymentNot started

Step 2 of 3

Delivery

Do

Name each step for what the reader does there, so they know what is coming.

  1. Step 1, completed.Done
  2. Step 2, current step.In progress
  3. Step 3Not started

Step 2 of 3

Step 2

Don't

Numbers alone say how far along the reader is, not what the steps are for.

Anatomy

  • The block, a div around everything.
  • The list part, an ordered list of the steps, named by the stepper's label.
  • The item part, a list item for each step. Its status is a modifier of the part: not started, current, unavailable, complete or error.
  • The step part, inside each item: a link or a button for a step the reader can go back to, a plain box for any other.
  • The marker row part: the marker part, a 24 circle holding the step's number part or its icon part (a check for a finished step, a warning sign for one with an error), and the connector part, the line on to the next step.
  • The text part: the label part, the step's name, and the status part, an optional line under it.
  • The hidden part: the step's status in words for screen readers.
  • The summary part: the count part ("Step 2 of 4") and the step name part, in the summary text part, over the track part, the progress bar's slim track.

Behavior

Horizontal lists the steps in a row, sharing its width; each line runs from a step's marker to the next step, and turns the brand's color after a finished step. Vertical lists them one under another, each name beside its marker and the line running down. Summary gives "Step 2 of 4", the current step's name and a slim track filled to that step. A horizontal stepper gives its summary instead of its row where the layout is narrow; nothing else changes. Long names wrap under their marker.

A step that is finished, or has an error, can be a link or a button back to it: it takes a fill under the pointer and the focus ring around the whole step. Steps not started, the current step and unavailable steps are never links. The summary names the current step; if no step is current, it names the first with an error, then the first not finished.

The stepper shows the steps; the page keeps them true. When the reader moves to another step, the page changes each step's status and moves focus to the new step's heading.

Accessibility


What it does for you

  • The steps are an ordered list, named by the stepper's label, such as "Checkout steps".
  • The current step's item carries aria-current="step", on one step only.
  • Each step's status is said in words after its name, such as "Your details, completed", in words only a screen reader hears. Where the visible status line already says the same words, they are left out.
  • The marker, its number and its icon are hidden from screen readers: the list gives the order and the words give the status.
  • A step that can be gone back to is a link or a button, a Tab stop, and Enter follows it. Other steps take no focus. There are no arrow keys: the stepper is not tabs.
  • A step that can be gone back to takes a fill under the pointer and the focus ring around the whole step.
  • The summary is named by the same label; its track repeats the count and is hidden from screen readers.
  • An unavailable step is marked with aria-disabled="true": it cannot be reached yet, and its name takes the disabled text color. Its line says why, such as "After payment", in the subtle text color, readable at full contrast.

What you must do

  • Give the stepper a label that names the steps, such as "Checkout steps".
  • Keep the steps true: when the reader moves to another step, change each step's status and move focus to the new step's heading.
  • In markup written by hand, add the status words in the hidden part.

How to test

  • Tab through the stepper: only finished steps and steps with an error that can be gone back to take focus, each with a focus ring round the whole step, and Enter goes back to it. The current step and steps not started are skipped.
  • With a screen reader, the steps are read as an ordered list by the label, each with its name and status words, and the current step as current.
  • With text at 200% and the page 320 pixels wide, long names wrap under their marker, and a horizontal stepper gives its summary instead of its row.
  • In a forced-color mode, the focus ring stays.

Keyboard

Stepper keys
KeyWhat it does
Tab
Moves focus to the next step that can be gone back to. Other steps are skipped.
Enter
Follows a step that is a link, or presses one that is a button.
Space
Presses a step that is a button.

Source


The files the stepper is made of. Its folder on GitHub (opens in a new tab) holds them with its wrapper and its document.

Stylesheet
stepper.css
/* smbk-stepper — Stepper. Figma "Stepper" 7117:303 and "Stepper item" 7117:227.
 * An ordered list of steps, each a 24 marker (its number in a ring, the brand fill for the current step, a
 * check for a finished one, a warning sign for one with an error), its name and a status line, with a line on
 * to the next step that turns brand after a finished step. A step the reader can go back to is a link or a
 * button over the whole step: the ghost fill under the pointer, the focus ring around it. The summary gives
 * "Step 2 of 4", the step's name and the progress bar's slim track; a horizontal stepper shows it instead of
 * its list where the layout is narrow. Each step's status is also said in words, for screen readers. */

.smbk-stepper {
  min-width: 0;
}

/* The block frames the words it hides for screen readers, so they stay inside it wherever it is placed: without a
   frame they hang from the page itself and stretch it, past the end of an area that scrolls. No weight, so a parent
   that places the block keeps its say. */
:where(.smbk-stepper) {
  position: relative;
}

.smbk-stepper__list {
  display: flex;
  gap: var(--smbk-space-0);
  min-width: 0;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Horizontal: the steps share the row equally. */
.smbk-stepper__item {
  display: flex;
  flex: 1 1 0;
  min-width: 0;
}

/* The step: the whole item, so its fill and its focus ring take in the line too. A link or a button when the
   reader can go back to it, a plain box otherwise. */
.smbk-stepper__step {
  box-sizing: border-box;
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: var(--smbk-space-stack-md);
  min-width: 0;
  margin: 0;
  padding: var(--smbk-space-inset-xs);
  border: 0;
  border-radius: var(--smbk-radius-control-md);
  background: none;
  color: inherit;
  font: inherit;
  text-align: start;
  text-decoration: none;
  appearance: none;
  -webkit-tap-highlight-color: transparent;
}

:where(a[href], button).smbk-stepper__step {
  cursor: pointer;
  touch-action: manipulation;
}

/* The marker and the line on to the next step. */
.smbk-stepper__marker-row {
  display: flex;
  align-items: center;
  gap: var(--smbk-space-inline-xs);
  min-width: 0;
}

.smbk-stepper__marker {
  box-sizing: border-box;
  display: flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: var(--smbk-size-control-xs);
  height: var(--smbk-size-control-xs);
  border: var(--smbk-border-width-emphasis) solid transparent;
  border-radius: var(--smbk-radius-full);
  color: var(--smbk-color-text-subtle);
}

.smbk-stepper__number {
  font-family: var(--smbk-typography-label-sm-font-family);
  font-size: var(--smbk-typography-label-sm-font-size);
  font-weight: var(--smbk-typography-label-sm-font-weight);
  line-height: var(--smbk-typography-label-sm-line-height);
  letter-spacing: var(--smbk-typography-label-sm-letter-spacing);
  text-transform: var(--smbk-typography-label-sm-text-transform);
  font-variant-numeric: tabular-nums;
}

.smbk-stepper__icon {
  font-size: var(--smbk-size-icon-xs);
}

.smbk-stepper__connector {
  flex: 1 1 auto;
  min-width: 0;
  height: var(--smbk-border-width-emphasis);
  background: var(--smbk-color-border-subtle);
}

/* The last step leads nowhere. */
.smbk-stepper__item:last-child .smbk-stepper__connector {
  display: none;
}

.smbk-stepper__text {
  display: flex;
  flex-direction: column;
  gap: var(--smbk-space-text-label);
  min-width: 0;
}

.smbk-stepper__label {
  color: var(--smbk-color-text-default);
  font-family: var(--smbk-typography-label-md-font-family);
  font-size: var(--smbk-typography-label-md-font-size);
  font-weight: var(--smbk-typography-label-md-font-weight);
  line-height: var(--smbk-typography-label-md-line-height);
  letter-spacing: var(--smbk-typography-label-md-letter-spacing);
  text-transform: var(--smbk-typography-label-md-text-transform);
  overflow-wrap: anywhere;
}

.smbk-stepper__status {
  color: var(--smbk-color-text-subtle);
  font-family: var(--smbk-typography-body-sm-font-family);
  font-size: var(--smbk-typography-body-sm-font-size);
  font-weight: var(--smbk-typography-body-sm-font-weight);
  line-height: var(--smbk-typography-body-sm-line-height);
  letter-spacing: var(--smbk-typography-body-sm-letter-spacing);
  text-transform: var(--smbk-typography-body-sm-text-transform);
  overflow-wrap: anywhere;
}

/* Words for screen readers only: each step's status. */
/* .smbk-stepper__hidden: hidden from view, kept for screen readers and the keyboard, by the shared rule in visually-hidden/visually-hidden.css. */

/* ---- status ---- */

.smbk-stepper__item--status-not-started .smbk-stepper__marker {
  border-color: var(--smbk-color-border-strong);
}

.smbk-stepper__item--status-current .smbk-stepper__marker {
  background: var(--smbk-color-action-brand-background);
  color: var(--smbk-color-action-brand-foreground);
}

.smbk-stepper__item--status-unavailable .smbk-stepper__marker {
  border-color: var(--smbk-color-border-control-disabled);
  color: var(--smbk-color-text-disabled);
}

.smbk-stepper__item--status-unavailable .smbk-stepper__label {
  color: var(--smbk-color-text-disabled);
}

.smbk-stepper__item--status-complete .smbk-stepper__marker {
  background: var(--smbk-color-action-secondary-background);
  color: var(--smbk-color-icon-default);
}

/* The line after a finished step is the brand's. */
.smbk-stepper__item--status-complete .smbk-stepper__connector {
  background: var(--smbk-color-border-brand);
}

.smbk-stepper__item--status-error .smbk-stepper__marker {
  background: var(--smbk-color-feedback-danger-surface);
  color: var(--smbk-color-feedback-danger-text-on-surface);
}

.smbk-stepper__item--status-error .smbk-stepper__status {
  color: var(--smbk-color-feedback-danger-text-on-subtle);
}

/* ---- a step the reader can go back to ---- */

@media (hover: hover) {
  :where(a[href], button:enabled).smbk-stepper__step:hover {
    background: var(--smbk-color-action-ghost-background-hover);
  }
}

:where(a[href], button:enabled).smbk-stepper__step:active {
  background: var(--smbk-color-action-ghost-background-pressed);
}

.smbk-stepper__step:focus-visible {
  outline: var(--smbk-focus-ring-width) solid var(--smbk-color-border-focus);
  outline-offset: var(--smbk-focus-ring-offset);
}

/* ---- vertical: one step under another, the label beside its marker and the line running down ---- */

.smbk-stepper--layout-vertical .smbk-stepper__list {
  flex-direction: column;
}

.smbk-stepper--layout-vertical .smbk-stepper__item {
  flex: none;
}

.smbk-stepper--layout-vertical .smbk-stepper__step {
  flex-direction: row;
  gap: var(--smbk-space-inline-md);
}

.smbk-stepper--layout-vertical .smbk-stepper__marker-row {
  flex-direction: column;
}

.smbk-stepper--layout-vertical .smbk-stepper__connector {
  width: var(--smbk-border-width-emphasis);
  height: auto;
  min-height: 0;
}

.smbk-stepper--layout-vertical .smbk-stepper__text {
  flex: 1 1 0;
}

/* ---- summary: "Step 2 of 4", the step's name, and a slim track ---- */

.smbk-stepper__summary {
  display: none;
  flex-direction: column;
  gap: var(--smbk-space-stack-md);
  min-width: 0;
}

.smbk-stepper--layout-summary .smbk-stepper__list {
  display: none;
}

.smbk-stepper--layout-summary .smbk-stepper__summary {
  display: flex;
}

.smbk-stepper__summary-text {
  display: flex;
  flex-direction: column;
  gap: var(--smbk-space-text-label);
  min-width: 0;
}

.smbk-stepper__count {
  margin: 0;
  color: var(--smbk-color-text-subtle);
  font-family: var(--smbk-typography-label-md-font-family);
  font-size: var(--smbk-typography-label-md-font-size);
  font-weight: var(--smbk-typography-label-md-font-weight);
  line-height: var(--smbk-typography-label-md-line-height);
  letter-spacing: var(--smbk-typography-label-md-letter-spacing);
  text-transform: var(--smbk-typography-label-md-text-transform);
}

.smbk-stepper__step-name {
  margin: 0;
  color: var(--smbk-color-text-default);
  font-family: var(--smbk-typography-heading-2xs-font-family);
  font-size: var(--smbk-typography-heading-2xs-font-size);
  font-weight: var(--smbk-typography-heading-2xs-font-weight);
  line-height: var(--smbk-typography-heading-2xs-line-height);
  letter-spacing: var(--smbk-typography-heading-2xs-letter-spacing);
  text-transform: var(--smbk-typography-heading-2xs-text-transform);
  overflow-wrap: anywhere;
}

/* A narrow space has no room for a row of steps: a horizontal stepper gives its summary instead. */
@container style(--smbk-layout: narrow) {
  .smbk-stepper--layout-horizontal .smbk-stepper__list {
    display: none;
  }

  .smbk-stepper--layout-horizontal .smbk-stepper__summary {
    display: flex;
  }
}

/* ---- high contrast (forced colors) ---- */
/* In Windows high-contrast mode the browser drops fills; this puts the markers and the lines back with the
   user's own colors. Nothing here applies outside that mode. */

@media (forced-colors: active) {
  .smbk-stepper__marker {
    forced-color-adjust: none;
    border-color: CanvasText;
    background: Canvas;
    color: CanvasText;
  }

  .smbk-stepper__item--status-current .smbk-stepper__marker {
    border-color: Highlight;
    background: Highlight;
    color: HighlightText;
  }

  .smbk-stepper__item--status-unavailable .smbk-stepper__marker {
    border-color: GrayText;
    color: GrayText;
  }

  .smbk-stepper__item--status-unavailable .smbk-stepper__label {
    color: GrayText;
  }

  .smbk-stepper__connector,
  .smbk-stepper__item--status-complete .smbk-stepper__connector {
    forced-color-adjust: none;
    background: CanvasText;
  }

  .smbk-stepper__step:focus-visible {
    outline-color: CanvasText;
  }
}
Tokens it reads
Stepper tokens
Token and CSSValuePreviewFoundation
space.0--smbk-space-00pxSpacing
space.stack.md--smbk-space-stack-mdcomfortable: 12pxcompact: 8pxchanges with densitySpacing
space.inset.xs--smbk-space-inset-xs4pxSpacing
radius.control.md--smbk-radius-control-md6pxRadius
space.inline.xs--smbk-space-inline-xs4pxSpacing
size.control.xs--smbk-size-control-xs24pxSize
border-width.emphasis--smbk-border-width-emphasis2pxBorder width
radius.full--smbk-radius-full9999pxRadius
color.text.subtle--smbk-color-text-subtlelight: #4e555edark: #9ba5b1changes with themeColor
typography.label-sm--smbk-typography-label-sm-font-family--smbk-typography-label-sm-font-size--smbk-typography-label-sm-font-weight--smbk-typography-label-sm-line-height--smbk-typography-label-sm-letter-spacing--smbk-typography-label-sm-text-transformfontFamily: Geist, Geist Fallback, system-ui, sans-seriffontSize: 12pxfontWeight: 500lineHeight: 1.4letterSpacing: 0px

The quick brown fox

Typography
size.icon.xs--smbk-size-icon-xs12pxSize
color.border.subtle--smbk-color-border-subtlelight: #c4cdd8dark: #2d3237changes with themeColor
space.text.label--smbk-space-text-label0pxSpacing
color.text.default--smbk-color-text-defaultlight: #232527dark: #e7ebf0changes with themeColor
typography.label-md--smbk-typography-label-md-font-family--smbk-typography-label-md-font-size--smbk-typography-label-md-font-weight--smbk-typography-label-md-line-height--smbk-typography-label-md-letter-spacing--smbk-typography-label-md-text-transformfontFamily: Geist, Geist Fallback, system-ui, sans-seriffontSize: 14pxfontWeight: 500lineHeight: 1.4letterSpacing: 0px

The quick brown fox

Typography
typography.body-sm--smbk-typography-body-sm-font-family--smbk-typography-body-sm-font-size--smbk-typography-body-sm-font-weight--smbk-typography-body-sm-line-height--smbk-typography-body-sm-letter-spacing--smbk-typography-body-sm-text-transformfontFamily: Geist, Geist Fallback, system-ui, sans-seriffontSize: 14pxfontWeight: 400lineHeight: 1.5letterSpacing: 0px

The quick brown fox

Typography
color.border.strong--smbk-color-border-stronglight: #9ba5b1dark: #373d43changes with themeColor
color.action.brand.background--smbk-color-action-brand-background#cc0d0dColor
color.action.brand.foreground--smbk-color-action-brand-foreground#f9fafbColor
color.border.control-disabled--smbk-color-border-control-disabledlight: #c4cdd8dark: #606a75changes with themeColor
color.text.disabled--smbk-color-text-disabledlight: #7c8692dark: #606a75changes with themeColor
color.action.secondary.background--smbk-color-action-secondary-backgroundlight: #373d4326dark: #606a7533changes with themeColor
color.icon.default--smbk-color-icon-defaultlight: #232527dark: #e7ebf0changes with themeColor
color.border.brand--smbk-color-border-brand#cc0d0dColor
color.feedback.danger.surface--smbk-color-feedback-danger-surface#cc0d0dColor
color.feedback.danger.text-on-surface--smbk-color-feedback-danger-text-on-surface#f9fafbColor
color.feedback.danger.text-on-subtle--smbk-color-feedback-danger-text-on-subtlelight: #a51d17dark: #febdb2changes with themeColor
color.action.ghost.background-hover--smbk-color-action-ghost-background-hoverlight: #373d4326dark: #606a754dchanges with themeColor
color.action.ghost.background-pressed--smbk-color-action-ghost-background-pressedlight: #c4cdd8dark: #2d3237Color
focus.ring.width--smbk-focus-ring-width2pxFocus
color.border.focus--smbk-color-border-focuslight: #cc0d0ddark: #f34336changes with themeColor
focus.ring.offset--smbk-focus-ring-offset2pxFocus
space.inline.md--smbk-space-inline-mdcomfortable: 8pxcompact: 6pxchanges with densitySpacing
typography.heading-2xs--smbk-typography-heading-2xs-font-family--smbk-typography-heading-2xs-font-size--smbk-typography-heading-2xs-font-weight--smbk-typography-heading-2xs-line-height--smbk-typography-heading-2xs-letter-spacing--smbk-typography-heading-2xs-text-transformfontFamily: Funnel Display, Funnel Display Fallback, system-ui, sans-seriffontSize: min: 18px · max: 24pxfontWeight: 400lineHeight: 1.2letterSpacing: 0px

The quick brown fox

Typography
Manifest
stepper.manifest.json
{
  "name": "stepper",
  "block": "smbk-stepper",
  "summary": "Where the reader is in a form or task of three or more ordered steps: each step's mark, name and status in words, joined by a line; or \"Step 2 of 4\" with the step's name and a slim track.",
  "adapt": "css",
  "axes": {
    "layout": {
      "values": [
        "horizontal",
        "vertical",
        "summary"
      ],
      "default": "horizontal",
      "description": "Horizontal lists the steps in a row and gives the summary instead where the layout is narrow. Vertical lists them one under another. Summary gives \"Step 2 of 4\", the step's name and a slim track at any width."
    }
  },
  "flags": {},
  "parts": [
    "list",
    "item",
    "step",
    "marker-row",
    "marker",
    "number",
    "icon",
    "connector",
    "text",
    "label",
    "status",
    "hidden",
    "summary",
    "summary-text",
    "count",
    "step-name",
    "track"
  ],
  "figmaNodeId": "7117:303"
}