A multi-step form is useful when a long task contains logical stages. It is not automatically better than a single page, and there is no universal number of fields or steps that guarantees completion.
The W3C multi-page forms tutorial recommends dividing long forms into smaller forms where possible, grouping controls logically, identifying optional stages, and telling people how far they have progressed. Those principles are more durable than a borrowed conversion percentage.
Decide whether the task needs stages
Use a single page when:
- the task is short enough to scan as a whole;
- all fields belong to one obvious information group;
- later questions do not depend on earlier answers;
- review and correction are easier in one view.
Use multiple steps when:
- the task has meaningful stages such as identity, details, review, and submission;
- later questions depend on previous answers;
- the person benefits from seeing only the current decision;
- validation or saving happens at safe stage boundaries;
- a review step prevents consequential submission mistakes.
Do not split a short form to create progress theatre. Every transition adds navigation, state, validation, and recovery work. A seven-step form with one field per screen can be harder to review than one well-grouped page.
Model the task before the component
Write a step table:
| Step | Purpose | Required data | Validation boundary | Can revisit? |
|---|---|---|---|---|
| 1 | Establish the subject | Identifying fields | Before continuing | Yes |
| 2 | Collect task details | Domain-specific fields | Before continuing | Yes |
| 3 | Review | No new data unless necessary | Whole-form checks | Yes |
| 4 | Submit | Confirmation | Server validation | No after acceptance |
Each step should have one clear heading and a coherent set of controls. Put optional fields or steps in plain language. If answers skip a future step, update the visible progress so it does not announce a route the person will never visit.
Separate:
- display order;
- validation schema;
- stored draft;
- server request;
- completed-step state.
These structures may overlap, but treating them as identical makes conditional branches and versioned drafts difficult to maintain.
Expose progress in text and semantics
For a known sequence, use an ordered list. Identify the current step in text and with aria-current="step". Allow navigation to completed steps only when entered data will be preserved.
On a narrow screen, “Step 2 of 4: Address” can be more useful than squeezing four labels into a horizontal strip. A progress bar can supplement that text if it has an accessible name and current value.
W3C also recommends putting progress in the page title or main heading for separate-page forms. In a client-rendered workflow, update the document title when the active step changes if doing so remains predictable for the application.
Never use colour alone for complete, current, and error states. Add text, an accessible name, or a distinct symbol. Decorative connector lines should be hidden from assistive technology.
Validate at the right boundary
Validation should help the person continue, not punish ordinary typing.
- Validate the current step before advancing.
- Preserve entered values after a validation failure.
- Identify every detected error in text.
- Associate inline messages with their fields.
- Put a focusable error summary before the controls when several errors exist.
- Move focus to the summary or first invalid field after a failed submission.
- Re-run full server validation before accepting the final request.
WCAG 2.2 error identification requires the item and problem to be described in text. An error summary can link to each invalid field, while inline messages provide local context.
Client validation is feedback. Server validation is the acceptance boundary. Never trust a completed-step set, hidden input, client-derived price, entitlement, or owner identifier.
Preserve work with an explicit data policy
Draft persistence can reduce accidental loss, but it can also leave sensitive data on a shared device. Decide:
- which fields may be stored locally;
- whether storage is session-only or persists after the browser closes;
- the draft expiry;
- how schema versions are handled;
- when the draft is deleted;
- whether the person must opt in;
- what must be stored server-side instead.
Do not place passwords, payment data, health details, identity documents, or other high-risk values in local storage merely because the form hook supports persistence.
Warn before leaving only when unsaved work would actually be lost. A persistent warning after successful submission is a bug.
Handle back, edit, and resume deliberately
The browser Back button should either navigate between form steps or leave the workflow. Mixing both behaviours unpredictably causes data loss. If the application maps steps to history state, test refresh, deep links, forward navigation, and a direct visit without prior state.
A review page should link back to completed sections and then return to review. Preserve the person’s position and explain whether editing a previous answer invalidates later answers.
When restoring a draft:
- validate its shape and version;
- discard corrupt or expired data safely;
- tell the person a draft exists;
- offer restore and discard actions;
- revalidate before submission.
A shared React architecture
The BY Group component set separates navigation state from form controls:
FormStepperrenders desktop and mobile progress;useMultiStepFormcontrols validated navigation, completed steps, optional browser history, edit-and-return, and draft persistence;ErrorSummaryfocuses a linked list of errors;StepNavigationowns previous, next, save, and submit actions;- the consuming product owns fields, domain schema, server mutation, and copy.
A simplified setup is:
const flow = useMultiStepForm({
totalSteps: steps.length,
onValidate: validateStep,
onStepChange: trackStepChange,
browserBackNavigation: true,
});
The hook is not a substitute for a form library or schema. It coordinates stages. Keep domain validation in the product so shared navigation code does not acquire unrelated business rules.
Accessibility and resilience checks
Test the workflow with:
- keyboard only;
- a screen reader;
- 200 percent zoom;
- a narrow viewport;
- reduced motion;
- JavaScript errors during save;
- a slow or failed final request;
- session expiry;
- refreshed and restored drafts;
- conditional steps;
- invalid values on multiple steps.
Loading states must not remove the current context. Disable duplicate submission while keeping the progress message available to assistive technology. On success, move to a clear confirmation state and remove any local draft.
Measure the actual task
Track only the events needed to diagnose the flow:
- form started;
- step viewed;
- validation failed by safe category;
- step completed;
- draft restored or discarded;
- review opened;
- submission accepted or rejected;
- confirmation shown.
Exclude field values and sensitive identifiers. Report completion by entry point, device class, and stable workflow version when those dimensions are appropriate. A drop at one step is a prompt for observation and testing, not proof that the step count caused it.
Release checklist
- Confirm that each step represents a logical task group.
- Write the step, branch, edit, and recovery model.
- Expose current and total progress in text.
- Preserve values and focus useful feedback after errors.
- Validate on both client and server.
- Review local and server draft storage against the data policy.
- test browser navigation, refresh, resume, and conditional paths.
- Verify every final mutation is authenticated and allow-lists fields.
- Confirm analytics contain no submitted values.
- Test confirmation and duplicate-submission behaviour.
The right form shape is the smallest structure that makes the task understandable and recoverable. Let the task determine the stages, then measure the actual journey.