# 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.

Block: `smbk-stepper`. Status: experimental. Figma: the Figma file, https://www.figma.com/community/file/1688324308358870630. Desktop and mobile: differ by presentation only.

## Options

| Axis | Values | Default | Meaning |
|---|---|---|---|
| `layout` | `horizontal`, `vertical`, `summary` | `horizontal` | 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. |

Parts: `smbk-stepper__list`, `smbk-stepper__item`, `smbk-stepper__step`, `smbk-stepper__marker-row`, `smbk-stepper__marker`, `smbk-stepper__number`, `smbk-stepper__icon`, `smbk-stepper__connector`, `smbk-stepper__text`, `smbk-stepper__label`, `smbk-stepper__status`, `smbk-stepper__hidden`, `smbk-stepper__summary`, `smbk-stepper__summary-text`, `smbk-stepper__count`, `smbk-stepper__step-name`, `smbk-stepper__track`

## Markup

```html
<div class="smbk-stepper smbk-stepper--layout-horizontal">
  <ol class="smbk-stepper__list" role="list" aria-label="Checkout steps">
    <li class="smbk-stepper__item smbk-stepper__item--status-complete">
      <a class="smbk-stepper__step" href="#">
        <span class="smbk-stepper__marker-row" aria-hidden="true">
          <span class="smbk-stepper__marker">
            <i
              class="ph ph-check smbk-icon smbk-icon--size-md smbk-stepper__icon"
              aria-hidden="true"
            ></i>
          </span>
          <span class="smbk-stepper__connector"></span>
        </span>
        <span class="smbk-stepper__text">
          <span class="smbk-stepper__label">Your details<span class="smbk-stepper__hidden">, completed.</span></span>
          <span class="smbk-stepper__status">Done</span>
        </span>
      </a>
    </li>
    <li class="smbk-stepper__item smbk-stepper__item--status-current" aria-current="step">
      <div class="smbk-stepper__step">
        <span class="smbk-stepper__marker-row" aria-hidden="true">
          <span class="smbk-stepper__marker">
            <span class="smbk-stepper__number">2</span>
          </span>
          <span class="smbk-stepper__connector"></span>
        </span>
        <span class="smbk-stepper__text">
          <span class="smbk-stepper__label">Delivery<span class="smbk-stepper__hidden">, current step.</span></span>
          <span class="smbk-stepper__status">In progress</span>
        </span>
      </div>
    </li>
    <li class="smbk-stepper__item smbk-stepper__item--status-not-started">
      <div class="smbk-stepper__step">
        <span class="smbk-stepper__marker-row" aria-hidden="true">
          <span class="smbk-stepper__marker">
            <span class="smbk-stepper__number">3</span>
          </span>
          <span class="smbk-stepper__connector"></span>
        </span>
        <span class="smbk-stepper__text">
          <span class="smbk-stepper__label">Payment</span>
          <span class="smbk-stepper__status">Not started</span>
        </span>
      </div>
    </li>
    <li class="smbk-stepper__item smbk-stepper__item--status-unavailable">
      <div class="smbk-stepper__step" aria-disabled="true">
        <span class="smbk-stepper__marker-row" aria-hidden="true">
          <span class="smbk-stepper__marker">
            <span class="smbk-stepper__number">4</span>
          </span>
          <span class="smbk-stepper__connector"></span>
        </span>
        <span class="smbk-stepper__text">
          <span class="smbk-stepper__label">Review<span class="smbk-stepper__hidden">, unavailable.</span></span>
          <span class="smbk-stepper__status">After payment</span>
        </span>
      </div>
    </li>
  </ol>
  <div class="smbk-stepper__summary" role="group" aria-label="Checkout steps">
    <div class="smbk-stepper__summary-text">
      <p class="smbk-stepper__count">Step 2 of 4</p>
      <p class="smbk-stepper__step-name">Delivery</p>
    </div>
    <div
      class="smbk-progress smbk-progress--tone-brand smbk-progress--size-sm smbk-progress--type-default smbk-progress--state-default smbk-stepper__track"
      aria-hidden="true"
    >
      <div class="smbk-progress__track">
        <span class="smbk-progress__fill" style="width:50%"></span>
      </div>
    </div>
  </div>
</div>
```

## React

```tsx
import { Stepper } from './design-system/components/stepper/stepper.js';

<Stepper layout="horizontal" label="Checkout steps" steps={[{ label: "Your details", status: "complete", statusText: "Done", href: "#" }, { label: "Delivery", status: "current", statusText: "In progress" }, { label: "Payment", status: "not-started", statusText: "Not started" }, { label: "Review", status: "unavailable", statusText: "After payment" }]} />
```

## Stylesheet

```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

```json
{
  "space": {
    "0": {
      "$type": "dimension",
      "$value": "0px",
      "$description": "Raw space step, 0 px. Only for fixed distances inside a component; spacing that follows density uses space/inset, stack or inline."
    },
    "stack": {
      "md": {
        "$type": "dimension",
        "$value": "{{space.12}}",
        "$description": "Gap between things stacked one above another, medium."
      }
    },
    "inset": {
      "xs": {
        "$type": "dimension",
        "$value": "{{space.4}}",
        "$description": "Padding inside a component, extra small."
      }
    },
    "inline": {
      "xs": {
        "$type": "dimension",
        "$value": "{{space.4}}",
        "$description": "Gap between things side by side, extra small."
      },
      "md": {
        "$type": "dimension",
        "$value": "{{space.8}}",
        "$description": "Gap between things side by side, medium."
      }
    },
    "text": {
      "label": {
        "$type": "dimension",
        "$value": "{{space.0}}",
        "$description": "Between a label or title and the line of supporting text right under it, inside a component. None: untrimmed line height already spaces the two lines."
      }
    }
  },
  "radius": {
    "control": {
      "md": {
        "$type": "dimension",
        "$value": "{{radius.6}}",
        "$description": "Corners of controls, medium."
      }
    },
    "full": {
      "$type": "dimension",
      "$value": "{{radius.9999}}",
      "$description": "Capsule: pills, chips, switches."
    }
  },
  "size": {
    "control": {
      "xs": {
        "$type": "dimension",
        "$value": "{{size.24}}",
        "$description": "Height of the extra-small control: 24 in both densities, the smallest target allowed. Dashboard recipe: use compact density; 40 for the page’s one main action and for forms; 32 for toolbars and filters, the size used most; 28 for actions inside table rows and cards. On phones switch to comfortable density, or give small controls an invisible 44 px tap area (size/target/comfortable)."
      }
    },
    "icon": {
      "xs": {
        "$type": "dimension",
        "$value": "{{size.12}}",
        "$description": "Icon box, extra small."
      }
    }
  },
  "border-width": {
    "emphasis": {
      "$type": "dimension",
      "$value": "{{border-width.2}}",
      "$description": "Two-pixel edges for emphasis: a chosen card, a focus ring."
    }
  },
  "color": {
    "text": {
      "subtle": {
        "$type": "color",
        "$value": "{{color.grey.700}}",
        "$description": "Secondary text: descriptions, metadata."
      },
      "default": {
        "$type": "color",
        "$value": "{{color.grey.900}}",
        "$description": "Main text."
      },
      "disabled": {
        "$type": "color",
        "$value": "{{color.grey.500}}",
        "$description": "Text in unavailable controls."
      }
    },
    "border": {
      "subtle": {
        "$type": "color",
        "$value": "{{color.grey.300}}",
        "$description": "Dividers and quiet edges."
      },
      "strong": {
        "$type": "color",
        "$value": "{{color.grey.400}}",
        "$description": "Stronger edges and separators."
      },
      "control-disabled": {
        "$type": "color",
        "$value": "{{color.grey.300}}",
        "$description": "A disabled control’s edge."
      },
      "brand": {
        "$type": "color",
        "$value": "{{color.red.600}}",
        "$description": "Brand-red edge; also the logo’s mark."
      },
      "focus": {
        "$type": "color",
        "$value": "{{color.red.600}}",
        "$description": "Keyboard focus ring on controls."
      }
    },
    "action": {
      "brand": {
        "background": {
          "$type": "color",
          "$value": "{{color.red.600}}",
          "$description": "Brand button and chip: fill at rest."
        },
        "foreground": {
          "$type": "color",
          "$value": "{{color.grey.50}}",
          "$description": "Brand button and chip: label and icon at rest."
        }
      },
      "secondary": {
        "background": {
          "$type": "color",
          "$value": "{{color.alpha.grey-800.15}}",
          "$description": "Secondary button: fill at rest."
        }
      },
      "ghost": {
        "background-hover": {
          "$type": "color",
          "$value": "{{color.alpha.grey-800.15}}",
          "$description": "Ghost button: fill on hover."
        },
        "background-pressed": {
          "$type": "color",
          "$value": "{{color.action.outline.background-pressed}}",
          "$description": "Ghost button: fill while pressed, one step past hover; also the current page in pagination."
        }
      }
    },
    "icon": {
      "default": {
        "$type": "color",
        "$value": "{{color.grey.900}}",
        "$description": "Icons."
      }
    },
    "feedback": {
      "danger": {
        "surface": {
          "$type": "color",
          "$value": "{{color.red.600}}",
          "$description": "Danger messages: strong fill."
        },
        "text-on-surface": {
          "$type": "color",
          "$value": "{{color.grey.50}}",
          "$description": "Danger messages: text on the strong fill."
        },
        "text-on-subtle": {
          "$type": "color",
          "$value": "{{color.red.700}}",
          "$description": "Danger messages: text on the pale fill."
        }
      }
    }
  },
  "typography": {
    "label-sm": {
      "$type": "typography",
      "$value": {
        "fontFamily": "Geist, Geist Fallback, system-ui, sans-serif",
        "fontSize": "12px",
        "fontWeight": 500,
        "lineHeight": 1.4,
        "letterSpacing": "0px"
      },
      "$description": "Label SM: labels on controls and short UI text (buttons, chips, tabs, menu headings). Geist Medium, sentence case. Code and keys use Code SM and Code MD."
    },
    "label-md": {
      "$type": "typography",
      "$value": {
        "fontFamily": "Geist, Geist Fallback, system-ui, sans-serif",
        "fontSize": "14px",
        "fontWeight": 500,
        "lineHeight": 1.4,
        "letterSpacing": "0px"
      },
      "$description": "Label MD: labels on controls and short UI text (buttons, chips, tabs, menu headings). Geist Medium, sentence case. Code and keys use Code SM and Code MD."
    },
    "body-sm": {
      "$type": "typography",
      "$value": {
        "fontFamily": "Geist, Geist Fallback, system-ui, sans-serif",
        "fontSize": "14px",
        "fontWeight": 400,
        "lineHeight": 1.5,
        "letterSpacing": "0px"
      }
    },
    "heading-2xs": {
      "$type": "typography",
      "$value": {
        "fontFamily": "Funnel Display, Funnel Display Fallback, system-ui, sans-serif",
        "fontSize": {
          "min": "18px",
          "max": "24px"
        },
        "fontWeight": 400,
        "lineHeight": 1.2,
        "letterSpacing": "0px"
      }
    }
  },
  "focus": {
    "ring": {
      "width": {
        "$type": "dimension",
        "$value": "{{border-width.2}}",
        "$description": "Thickness of the focus ring."
      },
      "offset": {
        "$type": "dimension",
        "$value": "{{space.2}}",
        "$description": "Gap between a control and its focus ring."
      }
    }
  }
}
```

## 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.

## 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.

## 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](list.md) of tasks with their status.
- Showing that something is loading or being worked on. Use the [progress bar](progress.md) or the [spinner](spinner.md).
- Switching between views of the same thing. Use [tabs](tabs.md).

## 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

| Key | What 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. |

## 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.
