Wizard / Stepper
A long task split into steps with a progress indicator, like Contact › Shipping › Payment › Review. Learn when to use steps, linear vs non-linear flows, validation, Back, drafts and URLs per step, and the data-loss bugs testers find in checkouts and bookings.
You’re booking a holiday apartment. Step 1, guests. Step 2, your address. Step 3, payment. You notice a typo in the address and press Back. The address form is empty. You type it all again, press Continue… and the payment step is empty too. Then the phone rings, you come back, refresh the page, and you’re on step 1 with nothing filled in.
A wizard turns one long, scary form into a few short ones. It also adds navigation and memory: which step am I on, what did I already enter, where does Back go? Every one of those is a place where a user’s work can quietly disappear.
What is it?
A wizard (also called a multi-step form or stepper) splits a long task into an ordered series of steps, one screen or section at a time, with a step indicator showing where you are: Contact › Shipping › Payment › Review. You’ll meet wizards in checkouts, bookings, sign-ups, loan and insurance applications, onboarding, and setup flows (“connect your smartwatch”).
Anatomy
Step 2 of a 4-step checkout wizard
- 1
Step indicator
Shows all steps, in order. A <nav> or list, with the current step marked aria-current="step".
- 2
Completed step
A check mark (not only a color). Usually clickable, so users can go back and change it.
- 3
Current step
Highlighted number and bold label. Must always match the form on screen.
- 4
Upcoming step
Outlined and muted. In a linear wizard it is not clickable yet.
- 5
Step title + progress text
"Step 2 of 4: Shipping". The same text screen readers should hear when the step opens.
- 6
Step content
Only the fields for this step. Validated when the user continues.
- 7
Back
Goes to the previous step and keeps everything the user entered.
- 8
Primary action
Says where it leads: "Continue to payment". On the last step: "Place order".
Linear or non-linear?
| Type | How it works | Good for |
|---|---|---|
| Linear | Steps in a fixed order. You can’t open step 3 before step 2 is valid. Completed steps can be revisited. | Checkouts, payments, anything where later steps depend on earlier ones |
| Non-linear | Every step can be opened at any time, in any order. The final step checks that everything is complete. | Profiles, settings, long applications users fill in over several days |
The indicator must make the rule visible: in a linear wizard, upcoming steps look (and are) not clickable; in a non-linear one, every step looks clickable and shows whether it’s done.
Designs & variants
Press Next step and Back under each example:
- Contact
- 2Shipping
- 3Payment
- 4Review
Shipping
Horizontal stepper
Web (desktop)Numbered circles with labels and connecting lines, as in MUI or Angular Material. Needs room: with 5+ steps or long labels, it won't fit a phone.
Contact· edit
- 2
Shipping
- 3
Payment
- 4
Review
Vertical stepper
Web / mobile webSteps stacked top to bottom with the current step's fields opened under its label. Fits narrow screens and long labels.
Step 2 of 4
Shipping
Compact progress
iOS / AndroidNative apps rarely show a full stepper. Typical: one screen per step, a thin progress bar, “Step 2 of 4”, and the navigation bar's back button.
- Cart
- Shipping
- Payment
- Review
Shipping
Checkout chevrons
Web shopsA custom arrow-shaped bar. It looks like breadcrumbs but shows steps in a process. Check it's clear which steps are done and which are clickable.
- Material steppers: Material Design (version 2) defined horizontal, vertical and mobile steppers. Material 3 no longer includes a stepper, but web libraries like MUI, Angular Material and Vuetify still ship one, so you’ll see that look everywhere.
- No native stepper on iOS or Android. Apps usually show one screen per step with a progress bar or “Step 2 of 4”, and use the navigation bar back button.
- Optional steps are labelled “Optional” and can be skipped. Error states mark a step with a red icon when it needs attention.
- Progress without labels (dots or a bar) is common in onboarding. It shows how far, but not what’s next.
When to use it
- The form is long (more than one screen of fields) and falls naturally into groups: who, where, how to pay.
- Later steps depend on earlier ones: shipping options depend on the address, payment options on the country.
- Users benefit from a review before committing: orders, bookings, applications, transfers.
- The task takes a while and users may pause and come back: then steps and drafts help a lot.
Good and bad uses
Five fields on one screen
A newsletter sign-up with email and name. One short form, one button.
A wizard for a short form
Step 1: email. Step 2: name. Step 3: done. Three loading screens, three chances to drop off, and nothing gained.
Tabs for sibling sections
A product page with Overview, Specs and Reviews: the user reads them in any order and nothing is “completed”. Use tabs.
Steps for sections without an order
A “wizard” for account settings where every step is independent. Users are forced through screens they didn’t want to change.
How good wizards behave
Validation happens per step
Each step checks its own fields when the user presses Continue, with clear error messagesError messageText that tells the user something went wrong and, ideally, how to fix it.Open in glossary → next to the fields, and doesn’t move on until they’re fixed. Don’t wait until the last step to say “ZIP code is invalid” without saying where. Also don’t validate the whole wizard on step 1 (“Payment method is required” before the user has seen payment). See text field for field-level input validationInput validationChecking that what the user typed is acceptable before the app uses it.Open in glossary →.
Back keeps everything
Back goes to the previous step with all its data still there. That includes choices like radio buttons and checkboxes, not just text. Going back and forward several times must never lose, duplicate or reset anything. This is state persistenceState persistenceWhether the app remembers what the user did after navigating away, rotating, or restarting.Open in glossary →, and it’s the first thing to test in any wizard.
Progress is saved
Users get interrupted: a phone call, a lost connection, a closed tab. Good wizards save a draft (in the browser, on the server, or both) so a refresh or a return visit lands on the same step with the same data, sometimes with a message like “Welcome back, you were on step 3”. Ask how long a draft lives, whether it follows the user to another device, and what’s not saved on purpose (card numbers and passwords usually aren’t).
On mobile, the same idea is state restorationState restorationBringing the user back to the same screen and data after the OS closed the app in the background.Open in glossary →: the OS can kill an app in the background, and the user should come back to the same step.
Every step has an address (web)
On the web, each step should change the URL: /checkout/shipping, /checkout/payment. Then the browser Back button goes to the previous step (not out of the checkout), Refresh stays on the step, and support can send a deep linkDeep linkA link that opens a specific screen inside an app instead of just its home screen.Open in glossary → to a specific step. Test what happens when you open a later step’s URL directly in a linear wizard: you should land on the first incomplete step, not on a half-broken payment page.
On Android, the system Back gesture or button should go to the previous step too. On iOS, the swipe from the left edge does the same in a navigation stack. If Back closes the whole flow, the user at least deserves a “Leave checkout? Your progress is saved” message.
Editing from the review page
The review step shows everything with Edit links. Edit opens that step, and saving should return to Review (“Save and return to review”), keeping every other step as it was. Walking the user through all later steps again, or worse, clearing them, is a common bug. One exception: if the change really affects later steps (a new country changes the shipping options), the wizard should say so and ask only for what changed.
Errors send the user to the right step
When the server rejects the order at the end (address can’t be delivered, card declined), the user should land on the step that needs fixing, with the error shown on the field, and their other data intact. A generic “Something went wrong” on the review page, or a restart from step 1, are both bugs.
The indicator never lies
The highlighted step, the “Step 2 of 4” text, the page title and the form on screen must always agree: after Continue, Back, browser Back, Edit, refresh and deep links.
Common bugs
| # | Bug | What you see | Typical severity |
|---|---|---|---|
| 1 | Back loses data | The previous step’s fields are empty after going back | High |
| 2 | Browser/system Back leaves the flow | One Back press and you’re out of the checkout | High |
| 3 | Indicator out of sync | “Step 3” is highlighted while step 2 is shown | Medium |
| 4 | Skipping required steps | Clicking the indicator opens Payment without a valid address | High |
| 5 | Edit from Review wipes later steps | After editing Shipping, Payment is empty again | Medium–High |
| 6 | No draft | Refresh or app restart goes back to step 1, empty | Medium–High |
| 7 | Errors on the wrong step | Server error shows on Review, the field to fix isn’t highlighted | Medium |
| 8 | Double submit | Pressing Place order twice creates two orders | Critical |
| 9 | Stale later steps | Changing the country keeps a shipping method that’s no longer available | Medium |
| 10 | Indicator doesn’t fit | Labels overlap or overflow on a 360 px screen | Low–Medium |
Stress-test it
A correct checkout wizard. Use Fill this step with test data to move fast. Try the browser Back, Forward and Reload buttons on every step, switch between Linear and Non-linear, and set the Server answer to Bad ZIP or Declined before you press Place order. Switch Layout to Phone to see a compact indicator, and watch what a screen reader hears.
Linear: steps you haven’t reached are locked in the indicator. Completed steps can be revisited.
shop.example.com/checkout/contact
Contact details
We'll send your receipt and delivery updates here.
Screen reader hears
- Step 1 of 4: Contact
Find the bug
This checkout has six bugs. The ticket’s acceptance criteria are in the panel below it. Explore like a tester:
- Fill the steps and go all the way to Review. Then go Back step by step.
- Use the browser Back and Forward buttons on step 2 or 3.
- On step 1, click Payment in the indicator.
- On Review, press Edit next to Contact or Shipping, then continue.
- On step 3, press Reload.
🐞 Bug hunt: Checkout wizard
This demo has 6 hidden bugs. Explore it like a tester, then check your findings.
shop.example.com/checkout
Checkout · Step 1 of 4: Contact
Contact details
We'll send your receipt and delivery updates here.
Tester tools
Acceptance criteria (from the ticket)
- Steps are completed in order. Only completed steps can be opened from the indicator.
- The indicator always shows the step on screen.
- Back (in the app or the browser) goes to the previous step and keeps what the user entered.
- Edit on Review opens that step, and saving returns to Review with everything else kept.
- The checkout is saved as a draft: a refresh returns to the same step with the data.
Network
- Requests appear here…
- 1
Hint: Fill Shipping, continue to Payment, then press the Back button under the form.
- 2
Hint: On step 2 or 3, press the browser Back button. Then press Forward.
- 3
Hint: Go to Payment, then press Back. Compare the indicator and the text above it with the form.
- 4
Hint: On step 1, click Payment or Review in the indicator.
- 5
Hint: Complete all steps. On Review, press Edit next to Shipping, then Continue.
- 6
Hint: Fill steps 1 and 2, then press Reload on step 3.
How to test it
Checklist
Wizard test checklist
0 of 13 checked
Example test cases
TC-WIZ-001Back keeps the previous step's datapositivehigh
Preconditions
- Cart with 2 items
Steps
- Complete Contact and Shipping (Express)
- On Payment, press Back
- Press Back again
Test data
Street: 1200 Lakeview Avenue, City: Portland, ZIP: 97205
Expected result
Shipping shows the same address and Express; Contact shows the same email and phone.
TC-WIZ-002Browser Back moves between stepspositivehigh
Steps
- Complete Contact and Shipping
- On Payment, press the browser Back button
- Press browser Forward
Expected result
Back opens /checkout/shipping with the data kept; Forward returns to /checkout/payment. The user never leaves the checkout.
TC-WIZ-003Cannot skip a required stepnegativehigh
Steps
- Open checkout (Contact step)
- Click Payment and Review in the indicator
- Open /checkout/payment directly in the address bar
Expected result
Payment and Review are not clickable; the direct URL redirects to the first incomplete step.
TC-WIZ-004Edit from Review returns to Reviewpositivemedium
Preconditions
- All steps completed, on Review
Steps
- Press Edit next to Shipping
- Change the street
- Press Save and return to review
Expected result
Review shows the new street; Contact and Payment are unchanged.
TC-WIZ-005Draft survives a refreshedgemedium
Steps
- Complete Contact and Shipping
- On Payment, refresh the page
- Close the tab, reopen the shop and go to checkout
Expected result
Both times the checkout opens on Payment with Contact and Shipping filled in.
TC-WIZ-006Declined payment returns to the Payment stepnegativehigh
Preconditions
- Test card that is always declined
Steps
- Complete all steps with the declining test card
- Press Place order
Expected result
The Payment step opens with "Your card was declined" next to the payment method. Other steps keep their data; no order is created.
TC-WIZ-007Step announced to screen readerspositivemedium
Steps
- Turn on VoiceOver or TalkBack
- Complete step 1 and continue
Expected result
The screen reader announces "Step 2 of 4: Shipping" (or reads the step heading, which has focus).
Tip: click a test case to expand it.
Tools
- The address bar and DevTools › Application (see DevTools for testers and cookies, sessions and storage): watch the URL change per step, and find the draft in Local Storage, Session Storage or a server request. Check no card number or CVC is stored there.
- DevTools › Network: see when each step is saved, and that Place order sends one request even if you double-click.
- Android: Developer options › Don’t keep activities to test the draft after the OS kills the app; test the system Back gesture on every step.
- iOS: swipe back from the left edge on every step; background the app for a while and return.
- Screen readers: VoiceOver, TalkBack or NVDA to hear the step changes.
Accessibility
- Announce the step. When a new step opens, move focus to its heading (“Step 2 of 4: Shipping”) or announce it in a live region. Otherwise a screen readerScreen readerSoftware that reads the screen aloud for blind and low-vision users, like VoiceOver or TalkBack.Open in glossary → user doesn’t know anything changed after pressing Continue.
- Mark the current step. Say each step’s state in text (“Contact, completed”). A check mark or color alone is not enough (WCAG 1.4.1 Use of Color, Level A).
Dev note
In the indicator use a list, witharia-current="step"on the current one. - Errors. Link error messages to their fields, move focus to the first invalid field or an error summary, and don’t rely on red alone. See ARIAARIAHTML attributes that tell assistive technology what custom elements are and what state they're in.Open in glossary → and text field.
Dev note
Errors are linked witharia-describedby. - KeyboardKeyboard navigationUsing a website with only the keyboard: Tab to move, Enter or Space to activate, Esc to close.Open in glossary →. Every field, the indicator links and Back / Continue reachable with Tab in a logical focus orderFocus orderThe order in which the Tab key moves through interactive elements.Open in glossary →. Enter in a field shouldn’t accidentally submit the whole order.
- Time limits. If the wizard times out (common in banking and ticket sales), warn the user and let them extend it (WCAG 2.2.1 Timing Adjustable, Level A).
- Don’t make them type it twice. WCAG 3.3.7 Redundant Entry (Level A) asks that information already entered in the same process is filled in or selectable, for example “Billing address same as shipping”. A Back button that clears fields fails users here too.
- Touch targetsTouch targetThe area of the screen that responds to a tap, which should be large enough for a finger.Open in glossary →. At least 44×44 pt on iOS and 48×48 dp on Android. On the web, WCAG 2.5.8 (AA) asks for at least 24×24 CSS px; 44×44 px (2.5.5, AAA) is the comfortable target. Small step circles in the indicator are a typical failure.
Mobile vs web
- No stepper component: each step is usually a screen pushed onto a navigation stack, with “Step 2 of 4” or a progress bar. The back button and the left-edge swipe must go to the previous step with data kept.
- A modal flow (sheet) may have Cancel instead of Back: does it ask “Discard your changes?” before throwing away a half-filled booking?
- Background the app on step 3 and come back later, and test Dynamic Type at the largest size: does the indicator still fit?
- No native stepper either: steps are usually screens or fragments. The system Back gesture/button must go to the previous step; if it closes the flow, it should confirm first.
- Test rotation and process death (Don’t keep activities): same step, same data afterwards.
- Check the keyboard (IME) doesn’t cover the Continue button on small screens, and that predictive back shows the previous step, not the screen before the wizard.
- Each step should have its own URL: test Back, Forward, Refresh, bookmarks and opening a later step directly.
- Test the draft: refresh, close the tab, open the site in a second tab (do the two tabs fight?), log in on another device.
- Check the responsive layout: at 360 px the horizontal indicator should switch to a compact or vertical version.
- Double submit: double-click Place order and check only one order is created.
Check your understanding
Quick quiz
0/6 answered · 0 correct
1.A user on step 3 of a checkout presses Back. What should they see?
2.On a web checkout, the browser Back button on the Payment step takes the user to the cart. What is the most likely cause?
3.In a linear wizard, the user is on step 1. What should happen when they click "Payment" (step 3) in the indicator?
4.The user presses Edit next to Shipping on the Review page and saves. Where should they land?
5.Which is NOT the +/− stepper from the component library?
6.How should a screen reader user learn that the next step has opened?
Key takeaways
- A wizard splits a long task into ordered steps with an indicator. It is not the +/− stepper.
- Use it for long forms with natural groups and dependencies; not for short forms or independent sections (use tabs).
- Back keeps data, always. Test in-app Back, browser or system Back, the indicator and Edit links.
- On the web, every step has a URL; a draft lets refresh and return visits continue where the user stopped.
- Linear wizards don’t let users skip ahead; Edit from Review returns to Review; server errors open the right step.
- The indicator never lies, and each new step is announced to screen readers (“Step 2 of 4: Shipping”).
Finished this page?Nice work, this page is complete!
Mark it as done to track your progress. It's saved in this browser, no account needed.
Its review cards are now in Bites ⚡