Component
Stepper and wizard
Numbered steps that show progress through a task, and the wizard recipe that validates each one.
Plain-text source, for agents and clipboard use: /components/source/stepper.txt
When to use it
A Stepper shows where someone is in a task with a fixed order: which steps are done, which is current and which remain. The wizard recipe pairs it with one form section per step, validates each step with the platform’s constraint checks before the next one opens, moves focus to the new step’s heading, and ends on a review that reads back what was entered. Numbering is the meaning here, so the markers are numbered.
Examples
Progress
Two steps done, the third current. Completed markers carry hidden text, so the tick is not the only signal.
- Completed: Lead traveller
- Completed: Departure
- 3Rooms
- 4Review
<ol class="flux-stepper" aria-label="New group booking">
<li class="flux-stepper__step" data-state="complete"><span class="flux-stepper__marker"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3.5 8.5l3 3 6-7" /></svg><span class="flux-visually-hidden">Completed: </span></span><span class="flux-stepper__label">Lead traveller</span></li>
<li class="flux-stepper__step" data-state="complete"><span class="flux-stepper__marker"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3.5 8.5l3 3 6-7" /></svg><span class="flux-visually-hidden">Completed: </span></span><span class="flux-stepper__label">Departure</span></li>
<li class="flux-stepper__step" aria-current="step"><span class="flux-stepper__marker">3</span><span class="flux-stepper__label">Rooms</span></li>
<li class="flux-stepper__step"><span class="flux-stepper__marker">4</span><span class="flux-stepper__label">Review</span></li>
</ol>With an error
A step that was completed and then invalidated, such as by a supplier declining, returns with an error state and hidden text that says so.
- Completed: Lead traveller
- Needs attention: Departure
- 3Rooms
- 4Review
<ol class="flux-stepper" aria-label="New group booking">
<li class="flux-stepper__step" data-state="complete"><span class="flux-stepper__marker"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3.5 8.5l3 3 6-7" /></svg><span class="flux-visually-hidden">Completed: </span></span><span class="flux-stepper__label">Lead traveller</span></li>
<li class="flux-stepper__step" data-state="error"><span class="flux-stepper__marker"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 4v4.5M8 11.5v.01" /></svg><span class="flux-visually-hidden">Needs attention: </span></span><span class="flux-stepper__label">Departure</span></li>
<li class="flux-stepper__step" aria-current="step"><span class="flux-stepper__marker">3</span><span class="flux-stepper__label">Rooms</span></li>
<li class="flux-stepper__step"><span class="flux-stepper__marker">4</span><span class="flux-stepper__label">Review</span></li>
</ol>Wizard
Press Next with the fields empty to see each step validate. Focus moves to the first field with a problem, and to each new step’s heading. The review reads back the answers, and submitting dispatches flux-wizard-complete.
<form class="flux-card flux-wizard" data-flux-wizard aria-labelledby="wizard-title">
<h2 class="flux-card__title" id="wizard-title">New group booking</h2>
<ol class="flux-stepper" aria-label="Steps">
<li class="flux-stepper__step" aria-current="step"><span class="flux-stepper__marker">1</span><span class="flux-stepper__label">Lead traveller</span></li>
<li class="flux-stepper__step"><span class="flux-stepper__marker">2</span><span class="flux-stepper__label">Departure</span></li>
<li class="flux-stepper__step"><span class="flux-stepper__marker">3</span><span class="flux-stepper__label">Review</span></li>
</ol>
<section class="flux-wizard__step" aria-labelledby="wizard-step-1">
<h3 class="flux-wizard__title" id="wizard-step-1">Lead traveller</h3>
<div class="flux-field" data-error="Enter the lead traveller’s full name.">
<label class="flux-field__label" for="wizard-name">Full name <span class="flux-field__required" aria-hidden="true">*</span></label>
<input class="flux-input" id="wizard-name" name="name" type="text" autocomplete="name" required />
</div>
<div class="flux-field" data-error="Enter an email address, for example anna@example.com.">
<label class="flux-field__label" for="wizard-email">Email <span class="flux-field__required" aria-hidden="true">*</span></label>
<input class="flux-input" id="wizard-email" name="email" type="email" autocomplete="email" required />
</div>
</section>
<section class="flux-wizard__step" aria-labelledby="wizard-step-2" hidden>
<h3 class="flux-wizard__title" id="wizard-step-2">Departure</h3>
<fieldset class="flux-choice-group" data-error="Choose a departure.">
<legend>Departure <span class="flux-field__required" aria-hidden="true">*</span></legend>
<label class="flux-choice"><input class="flux-radio" type="radio" name="departure" value="GC-0914" required /> Golden Circle Classic, 14 Sep</label>
<label class="flux-choice"><input class="flux-radio" type="radio" name="departure" value="SC-0919" required /> South Coast Explorer, 19 Sep</label>
<label class="flux-choice"><input class="flux-radio" type="radio" name="departure" value="SN-0922" required /> Snæfellsnes Peninsula, 22 Sep</label>
</fieldset>
<div class="flux-field" data-error="Enter between 1 and 49 travellers.">
<label class="flux-field__label" for="wizard-pax">Travellers <span class="flux-field__required" aria-hidden="true">*</span></label>
<input class="flux-input" id="wizard-pax" name="pax" type="number" inputmode="numeric" min="1" max="49" required />
</div>
</section>
<section class="flux-wizard__step" aria-labelledby="wizard-step-3" hidden>
<h3 class="flux-wizard__title" id="wizard-step-3">Review</h3>
<dl class="flux-dl">
<div class="flux-dl__pair"><dt class="flux-dl__term">Lead traveller</dt><dd class="flux-dl__detail" data-flux-review="name"></dd></div>
<div class="flux-dl__pair"><dt class="flux-dl__term">Email</dt><dd class="flux-dl__detail" data-flux-review="email"></dd></div>
<div class="flux-dl__pair"><dt class="flux-dl__term">Departure</dt><dd class="flux-dl__detail" data-flux-review="departure"></dd></div>
<div class="flux-dl__pair"><dt class="flux-dl__term">Travellers</dt><dd class="flux-dl__detail flux-dl__detail--data" data-flux-review="pax"></dd></div>
</dl>
</section>
<div class="flux-wizard__actions">
<button class="flux-button flux-button--secondary" type="button" data-flux-wizard-back hidden>Back</button>
<button class="flux-button" type="button" data-flux-wizard-next>Next</button>
<button class="flux-button" type="submit" data-flux-wizard-submit hidden>Create booking</button>
</div>
</form>Anatomy
| Part | Description |
|---|---|
| Stepper | An ordered list labelled for the task. |
| Step | A marker and a label. aria-current="step" on the current one; data-state="complete" or "error" on others. |
| Marker | A near-square box with the number in mono, a tick when complete, or an alert mark on error. |
| Connector | A hairline after each step that turns teal once the step is complete. |
| Wizard step | A section with a heading per step. Only the current one is shown. |
| Actions | Back on the left, Next or the final submit on the right, below a hairline. |
API
| Name | Kind | Description |
|---|---|---|
flux-stepper | class | On the ol. Label it for the task. |
flux-stepper__step | class | On each li. |
flux-stepper__marker | class | The number, or a tick or alert icon with hidden text. |
flux-stepper__label | class | The step name. Below 48rem only the current step keeps its visible label. |
aria-current="step" | attribute | On the current step. |
data-state | attribute | "complete" or "error" on a step that is not current. |
data-flux-wizard | attribute | On the form. Wires the steps, the stepper, validation and the review. |
flux-wizard__step | class | On each section. Hide all but the first in the markup. |
flux-wizard__title | class | The step heading. Receives focus when its step opens. |
flux-wizard__actions | class | The action row. |
data-flux-wizard-back | -next | -submit | attribute | On the three buttons. The script shows the right ones for each step. |
data-error | attribute | On a flux-field or choice group: the message shown when its control is invalid. Without it the browser’s message is used. |
data-flux-review | attribute | On an element in the review: the name of the field whose value it shows. For radios, the checked option’s label. |
flux-wizard-complete | element | Cancelable event dispatched on the form when every step is valid and it is submitted. Call preventDefault to submit by script instead. |
States
| State | Treatment |
|---|---|
| Upcoming | A border-strong marker with the number in text-secondary. |
| Current | A teal filled marker with the number in text-on-color; the label is bold text-primary. |
| Complete | A teal outlined marker with a tick, and a teal connector after it. |
| Error | An error outlined marker with an alert mark, and the label in text-error. |
| Invalid field | aria-invalid on the control and an error message below it, bound with aria-describedby. The message clears once the value is valid. |
Keyboard
| Keys | Action |
|---|---|
Tab | Moves through the fields of the current step, then Back and Next. |
Enter | In a field, submits the form, which validates every step and opens the first one with a problem. |
Accessibility
- The stepper is a list, so its length and each position are announced; aria-current marks the current step.
- Completed and error markers carry hidden text, so the icon and colour are not the only signal.
- Moving to a step focuses its heading, so screen reader users hear where they are.
- An invalid step keeps focus on its first invalid field, with the message bound to it.
Tokens
The tier-3 and tier-2 tokens this component binds to. Change the token, not the component.
- --flux-stepper-marker-size | -gap
- --flux-stepper-connector | -connector-complete
- --flux-stepper-marker-border | -marker-text
- --flux-stepper-marker-current-bg | -marker-current-text
- --flux-stepper-marker-complete | -marker-error
- --flux-stepper-label | -label-current
Do and don’t
Do
- Keep a wizard to three to six steps, each a coherent group of fields.
- End on a review that reads back what will be submitted.
- Keep answers when someone goes back a step.
Don’t
- Do not make the steps clickable when they must be done in order.
- Do not validate a step before someone tries to leave it.
- Do not use a wizard for a form that fits on one screen.