Skip to Content
Component ExamplesMulti-Step Forms

Multi-Step Forms / Wizards

Step indicators, focus management between steps, and WCAG 2.2's Redundant Entry requirement.

Maintained by Martin KrugerLast reviewed

Overview

Multi-step forms (wizards) break long forms into manageable chunks, but they introduce serious accessibility problems when step transitions are visual-only. A sighted user sees the step indicator change and the new fields appear, but a screen reader user may be stranded at the top of the page with no idea that the form has moved to step 2. The step indicator itself is often a set of styled spans with no semantic meaning — screen readers cannot determine which step is current. WCAG 2.2 introduced 3.3.7 Redundant Entry, which requires that information previously entered by the user must be auto-populated or available for selection if needed again in a later step.

WCAG Criteria:

Key requirements:

  • Use an <ol> for the step indicator so screen readers convey the sequence and total number of steps
  • Mark the current step with aria-current="step" so assistive technology can identify it programmatically
  • On step transition, move focus to the new step’s heading (with tabindex="-1") so screen readers announce the new context
  • Validate the current step’s fields before advancing — do not let the user skip to step 2 with empty required fields
  • Preserve values when users move Back so they can review and edit them; this is essential usability, but is not by itself the test in 3.3.7
  • When a later step asks for information already supplied in the same process, auto-populate it or make it selectable unless an exception applies (WCAG 3.3.7)
  • Provide Back and Next buttons so users can navigate between steps without losing data

Wizard Steps

Silent Step Change vs. Managed Focus Wizard

Inaccessible
1 2

Step 1: Personal Info

View inaccessible code
<!-- Step indicator with no semantic structure or current-step indication --> <div style="display: flex; gap: 8px;"> <span>1</span> <span>2</span> </div> <!-- Step 1 --> <div id="step1"> <p>Step 1: Personal Info</p> <label>Name</label> <input type="text" /> <label>Email</label> <input type="email" /> <button onclick=" document.getElementById('step1').style.display = 'none'; document.getElementById('step2').style.display = 'block'; ">Next</button> </div> <!-- Step 2 — focus stays at page top, no Back button --> <div id="step2" style="display: none;"> <p>Step 2: Address</p> <label>Street</label> <input type="text" /> <label>City</label> <input type="text" /> <button>Submit</button> </div>
Accessible

Step 1 of 2: Personal Info

View accessible code
<!-- Semantic step indicator with aria-current --> <nav aria-label="Form progress"> <ol> <li aria-current="step">1</li> <li>2</li> </ol> </nav> <!-- Step 1 — heading receives focus on Back navigation --> <div id="step1"> <h3 id="heading1" tabindex="-1">Step 1 of 2: Personal Info</h3> <label for="name">Name</label> <input id="name" type="text" required /> <label for="email">Email</label> <input id="email" type="email" required /> <div id="error" role="alert"></div> <button onclick=" if (!name.value || !email.value) { error.textContent = 'Please fill in all required fields.'; return; } step1.style.display = 'none'; step2.style.display = 'block'; heading2.focus(); ">Next</button> </div> <!-- Step 2 — heading receives focus on Next navigation --> <div id="step2" style="display: none;"> <h3 id="heading2" tabindex="-1">Step 2 of 2: Address</h3> <label for="street">Street</label> <input id="street" type="text" /> <label for="city">City</label> <input id="city" type="text" /> <button onclick=" step2.style.display = 'none'; step1.style.display = 'block'; heading1.focus(); ">Back</button> <button>Submit</button> </div>

What’s wrong with the silent step change?

  • The step indicator uses unsemantic <span> elements — screen readers have no way to determine the total number of steps or which step is current
  • No aria-current="step" — the visual highlight on the active step number is invisible to assistive technology
  • When the user clicks “Next”, focus stays wherever it was — a screen reader user has no indication that new form fields have appeared
  • No validation before advancing — the user can proceed with empty required fields and encounter errors later
  • No “Back” button — users cannot return to a previous step to review or correct their input
  • Previously entered data may be lost when navigating between steps, forcing avoidable recovery work

Programmatic behavior to verify:

ActionInaccessible versionAccessible version
Reading step indicatorTwo unlabelled numbers with no current stateA labelled navigation list whose active item exposes aria-current="step"
Activating NextFocus remains on a control that has been hiddenFocus moves to the newly visible step heading
Activating BackNo Back controlPrevious values remain available and focus moves to the restored step heading
Empty fields on NextThe step changes without validationA persistent empty alert is populated with the validation message

Exact spoken output varies by screen reader, browser, settings, and language.

Why aria-current="step" matters:

  • aria-current="step" is specifically designed for step indicators in wizards — it tells screen readers “this is the step the user is currently on”
  • Without it, a screen reader user navigating the step indicator hears a list of numbers with no way to know which is active
  • The value "step" (not "true" or "page") is the semantically correct token for multi-step processes

Why focus management is critical:

  • When content changes dynamically, screen readers continue reading from the current cursor position
  • If focus is not moved to the new step heading, the user may not realize the form has changed at all
  • tabindex="-1" on the heading allows programmatic focus without adding the heading to the natural tab order

Key Teaching Points

TechniquePurposeWhere to apply
<ol> for step indicatorConvey sequence and total step countOn the step indicator container
aria-current="step"Identify the current step programmaticallyOn the active <li> in the step indicator
tabindex="-1" + .focus()Move focus to new step on transitionOn each step’s heading element
role="alert"Announce validation errors immediatelyOn the error message container
Validate before advancingPrevent skipping required fieldsIn the Next button’s click handler
Preserve entered dataLet users review and correct earlier stepsRetain input values when navigating Back
Reuse informationMeet WCAG 3.3.7 when the same information is requested againPre-fill or offer previously entered addresses, contact details, or other data

Redundant Entry is about repeated requests

Keeping a field value when the user goes Back is good state management. WCAG 3.3.7 applies when the process asks for the same information again, such as requesting a billing address and then a shipping address. Offer “Same as billing address,” pre-fill the later fields, or let the user select the prior address. Re-entry can still be required when it is essential, needed for security, or the previous information is no longer valid.

Page title and step heading are different

The visible step heading identifies the current section and is a useful focus target. WCAG 2.4.2 applies to the document’s <title>. If each step is a separate page, give each document a descriptive title such as “Address — Checkout.” If steps update one document in place, changing the document title can help orientation and history, but it is not replaced by an <h3>.


Resources