Skip to Content
Component ExamplesMulti-Step Forms

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
  • Auto-populate or display previously entered data when returning to a step (WCAG 3.3.7 Redundant Entry)
  • Provide Back and Next buttons so users can navigate between steps without losing data

Wizard Steps

Silent Step Change vs. Managed Focus Wizard

Inaccessible
<!-- 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>
Live Preview
1 2

Step 1: Personal Info

Accessible
<!-- 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>
Live Preview

Step 1 of 2: Personal Info

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, violating WCAG 3.3.7

What the screen reader announces:

ActionInaccessible versionAccessible version
Reading step indicator”1 2” (meaningless text)“Form progress, navigation, list, 2 items, Step 1, current step”
Clicking NextNothing — focus stays at button”Step 2 of 2: Address, heading level 3”
Clicking BackN/A (no Back button)“Step 1 of 2: Personal Info, heading level 3”
Empty fields on NextNothing — silently advances”Please fill in all required fields before continuing” (via role=“alert”)

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 dataComply with WCAG 3.3.7 Redundant EntryRetain input values when navigating Back

Resources