Stepper

Use a stepper for tasks with 3–5 dependent steps or more than ~8 fields: invoice import "Datei wählen › Spalten zuordnen › Prüfen", exam day "Vorbereiten › Prüfungstag › Abschluss › Abrechnung" (UX guide §4.4–4.5).

Steps are named by what the person does. current is the zero-based index of the active step; steps before it are rendered as done (check mark), steps after it as upcoming. The last step is a review that shows exactly what will happen before the commit button.

Two forms (design guide §9.6): from 768 px the numbered steps sit in a row — done: check in an accent circle; current: accent ring and semibold label; upcoming: --color-border-strong ring and muted label. Below 768 px it collapses to "Schritt 2 von 3" plus a progress bar; the step list stays available to screen readers.

The stepper is an indicator, not navigation: each step has its own URL and the page provides "Zurück"/"Weiter" buttons. Progress is saved per step so leaving and returning resumes.

Examples

Exam day

  1. Vorbereiten, erledigt
  2. Prüfungstag
  3. Abschluss
  4. Abrechnung
Data
render({
  "steps": [
    "Vorbereiten",
    "Prüfungstag",
    "Abschluss",
    "Abrechnung"
  ],
  "current": 1
})
Markup
<div class="stepper">
<div class="stepper__compact" aria-hidden="true"><p class="stepper__count">Schritt 2 von 4</p><progress class="progress" max="4" value="2"></progress></div>
<ol class="stepper__steps" aria-label="Fortschritt"><li data-state="done"><span class="stepper__marker" aria-hidden="true"><svg class="icon" data-size="sm" aria-hidden="true"><use href="../../packages/ui/icons/icons.svg#check"/></svg></span><span class="stepper__label">Vorbereiten</span><span class="u-visually-hidden">, erledigt</span></li><li aria-current="step"><span class="stepper__marker" aria-hidden="true">2</span><span class="stepper__label">Prüfungstag</span></li><li><span class="stepper__marker" aria-hidden="true">3</span><span class="stepper__label">Abschluss</span></li><li><span class="stepper__marker" aria-hidden="true">4</span><span class="stepper__label">Abrechnung</span></li></ol>
</div>

Invoice import, last step

  1. Datei wählen, erledigt
  2. Spalten zuordnen, erledigt
  3. Prüfen
Data
render({
  "label": "Rechnungen importieren",
  "steps": [
    "Datei wählen",
    "Spalten zuordnen",
    "Prüfen"
  ],
  "current": 2
})
Markup
<div class="stepper">
<div class="stepper__compact" aria-hidden="true"><p class="stepper__count">Schritt 3 von 3</p><progress class="progress" max="3" value="3"></progress></div>
<ol class="stepper__steps" aria-label="Rechnungen importieren"><li data-state="done"><span class="stepper__marker" aria-hidden="true"><svg class="icon" data-size="sm" aria-hidden="true"><use href="../../packages/ui/icons/icons.svg#check"/></svg></span><span class="stepper__label">Datei wählen</span><span class="u-visually-hidden">, erledigt</span></li><li data-state="done"><span class="stepper__marker" aria-hidden="true"><svg class="icon" data-size="sm" aria-hidden="true"><use href="../../packages/ui/icons/icons.svg#check"/></svg></span><span class="stepper__label">Spalten zuordnen</span><span class="u-visually-hidden">, erledigt</span></li><li aria-current="step"><span class="stepper__marker" aria-hidden="true">3</span><span class="stepper__label">Prüfen</span></li></ol>
</div>

Data contract

What render(data) accepts — validated against this JSON Schema in development and tests. Unknown fields are rejected. The same schema is in components.json.

FieldTypeRequiredDefaultDescription
labelstringoptional"Fortschritt"Accessible name of the list ("Fortschritt", "Prüfungstag").
stepsarray of stringrequired—Step names in order (max 5), verbs or task names ("Datei wählen").
min 2 items · max 5 items
currentintegerrequired—Zero-based index of the current step. Earlier steps are done. Use steps.length to mark all as done.
≥ 0
doneLabelstringoptional"erledigt"Visually hidden suffix announced after done steps ("Vorbereiten, erledigt").
JSON Schema
{
  "type": "object",
  "additionalProperties": false,
  "required": [
    "steps",
    "current"
  ],
  "properties": {
    "label": {
      "type": "string",
      "default": "Fortschritt",
      "description": "Accessible name of the list (\"Fortschritt\", \"Prüfungstag\")."
    },
    "steps": {
      "type": "array",
      "minItems": 2,
      "maxItems": 5,
      "description": "Step names in order (max 5), verbs or task names (\"Datei wählen\").",
      "items": {
        "type": "string",
        "minLength": 1,
        "description": "One step name."
      }
    },
    "current": {
      "type": "integer",
      "minimum": 0,
      "description": "Zero-based index of the current step. Earlier steps are done. Use `steps.length` to mark all as done."
    },
    "doneLabel": {
      "type": "string",
      "default": "erledigt",
      "description": "Visually hidden suffix announced after done steps (\"Vorbereiten, erledigt\")."
    }
  }
}

Markup & states

Root: div.stepper — usable without render() by writing the markup directly.

Attributes

AttributeValuesDefaultDescription
aria-label (on .stepper__steps)text—Names the progress list.

Parts

PartDescription
.stepper__compactMobile form (< 768 px): .stepper__count ("Schritt 2 von 4") and a .progress bar. aria-hidden, because the list below says the same.
.stepper__stepsThe <ol> of steps: a row from 768 px, visually hidden (still read) below.
.stepper__markerCircle with the step number, or a check icon on done steps (decorative).
.stepper__labelStep name.
.u-visually-hiddenAnnounced state of done steps.

States

StateDescription
li[data-state="done"]Done: check in an accent-filled circle.
li[aria-current="step"]Current: accent ring, semibold label.
li (no state)Upcoming: --color-border-strong ring, muted label.

Accessibility

  • Ordered list, so screen readers announce "Liste, 4 Einträge" and positions — also on phones, where it is visually replaced by the compact form.
  • The current step has aria-current="step"; done steps add a visually hidden "erledigt" — state is never colour-only.

Guidance

DoName steps by what the person does.
DoEnd with a review step showing the consequences, then a verb button ("3 Rechnungen erstellen").
Don'tDon't use more than 5 steps.
Don'tDon't use a stepper for independent sections — use tabs or a long form with headings.

Related: Tabs · Progress bar · Page header