Lesson 4 of 4 · 60 min

Make form failures usable without a mouse

Specify validation, pending, error, and success behavior for an accessible save flow.

A reliable form communicates what happened and what the user can do next. A disabled button or a red border is only part of that communication. Users may navigate with a keyboard, use a screen reader, or return after an interrupted request. The form needs a state model that preserves input and exposes actionable status.
Validate near the field when the rule is local and deterministic, but keep the server authoritative. A required name can be checked before submission. A unique project slug still needs a server decision because another user may claim it. Client validation should reduce avoidable attempts, not create a false guarantee that the server must accept the data.
Associate an error message with its field and describe the correction. A message that says invalid is weaker than one that says the slug must contain lowercase letters, digits, or hyphens. A summary can link to invalid fields when several fields fail. Move focus deliberately when that helps the user find the problem, and do not move it unexpectedly on every keystroke.
Asynchronous status needs an announcement strategy. W3C's form guidance discusses notifying users of errors and successful completion. Choose an appropriate live region or focus behavior for the interface. Avoid repeating the whole form on every progress event. A status such as saving can become saved or could not save, with the input retained. A timeout may require confirmation pending rather than a false failed label.

Worked example

A fictional profile form has display name and public slug. The user submits name Mina and slug Team Space. Client validation identifies the space and associates a message with the slug field. After correction to team-space, the server rejects the slug as taken. The form keeps Mina and team-space, focuses the error summary, and offers a link to the slug field. The user changes it to team-space-7 and saves successfully.
The success message announces that the profile was saved. Focus remains in a sensible position rather than jumping to the top of the page. The saved indicator describes the submitted version. If the user edits again before completion, the form distinguishes saved fields from newer unsaved input.

Write the form-state table

A form's interaction contract should distinguish local validation, server rejection, transport uncertainty, and successful persistence. The following table is an original design for a project-settings form.
StateInput retained?Visible messageNext action
Local field invalidYesSpecific field ruleCorrect field
Saving submitted revisionYesSaving current submitted versionWait or keep editing under policy
Server conflictYesCurrent value differsReconcile intentionally
Permission deniedAs allowed by policyNo longer allowed to saveReview access or copy draft safely
Outcome unknownYesConfirmation pendingRecover same operation
SavedYesSubmitted version savedContinue editing if needed
The message should identify what the system knows. A network error after possible commit is not the same as a server validation rejection. The interface may need to keep the submit button from creating a new operation while resolving the old one. It can still let the user edit locally if it tracks that newer intent separately.

Inspect an accessible error artifact

This simplified HTML illustrates a field error association. It is a teaching fragment, not a complete form or a claim that this markup alone meets every accessibility requirement.
html
1Public slug23<p id="slug-help">Use lowercase letters, digits, and hyphens.</p>4<p id="slug-error">This slug is already in use. Choose another.</p>
The label identifies the control. The described-by relationship connects help and error text. The invalid state communicates the current problem. A complete page also needs logical focus order, visible focus, suitable contrast, keyboard access, and a notification strategy for errors that appear after submission. Do not assume that adding one ARIA attribute replaces testing the actual user flow.
A multi-error response can include a summary with links to fields. If focus moves to the summary after submit, the user should be able to follow a link to the relevant control. Avoid moving focus on every validation keystroke because that disrupts typing. A live region can announce status changes, but repeated noisy announcements can make the form harder to use. Choose the smallest useful update.

A second asynchronous schedule

The user submits revision 4 with slug team-space. While saving, they edit the name, creating revision 5. The server rejects the slug for revision 4. The form should associate the slug error with the submitted value and preserve the newer name. If the user already changed the slug to another value before the rejection arrives, avoid presenting the old error as if it necessarily applies to the new value.
One approach attaches validation results to the submitted field values or draft revision. For a cross-field rule, such as start date before end date, its dependency set includes both fields. An unchanged start date does not make the old ordering error applicable if the end date changed. Reuse a validation result only when the inputs on which it depends still match, or revalidate the current values. The interface can say the previous slug was taken while allowing the new value to be checked. The precise wording depends on the product, but the core rule is that an error belongs to the request that produced it. This is the same identity reasoning used for successful responses.

Misconceptions to correct

The first misconception is that a red border is enough. Color alone may not communicate the problem or the repair, and some users do not perceive it. Provide text and a programmatic relationship appropriate to the control.
The second misconception is that a transient toast provides complete error recovery. A toast may disappear before the user reads it and may not identify the field. Keep actionable errors where the user can return to them, and announce changes without relying only on visual timing.
A third failure is clearing a form after any server error. It destroys valid work and makes correction harder. Preserve input unless the product's security or action contract requires a different behavior, and explain that behavior explicitly.

Extend the exercise

A server returns two errors: slug taken and start date after end date. Write the summary and field associations. A model summary says two fields need attention and links to the slug and date group. The slug error names the collision; the date error explains the ordering rule. Award one point for retaining values, one for useful error text, one for associations, and one for a keyboard path from summary to correction.

Exercise and solution

The server returns a transient error after the user enters five fields. Design the response. Preserve every entered value, provide an accessible status message, and allow a controlled retry using the same logical save identity if required by the API. Award one point for each. Clearing the form or relying only on color fails the exercise because it increases work and hides the correction path.

Interview probe and wrap-up

When should a submit button remain enabled during a request? A strong answer starts with the interaction contract and duplicate-operation protection. It may disable repeat submission while preserving navigation and feedback, or support deliberate repeated actions with separate identities. Follow up with keyboard focus on a disabled control. A weak answer treats accessibility as labels added after implementation. Include failure recovery and announcements in the original state model.

Sources

docsW3C accessible form notificationsw3.orgdocsReact state snapshotsreact.dev

Checkpoint

A server error arrives for an older submitted slug after the user changed it. What should the UI consider?

AMark the new slug valid because it differs.BApply the error to any current slug without checking.CAssociate the error with the submitted value or revision.DClear the new slug automatically.
Sign up free to answer and see why

Checkpoint

What does aria-describedby contribute in the shown fragment?

AIt guarantees immediate announcement of every error change.BIt moves keyboard focus to the error as soon as text changes.CIt supplies the input's accessible name in place of its label.DIt connects help/error text to the control.
Sign up free to answer and see why

Checkpoint

Why can focus movement on every keystroke be harmful?

AIt guarantees better error discovery.BIt can interrupt typing and navigation unexpectedly.CIt is required whenever an invalid field has help text.DIt preserves the typing position whenever the focus target is an error summary.
Sign up free to answer and see why

Checkpoint

A save times out after possible commit. Which message is accurate?

AConfirmation pending while the same operation is resolved.BDefinitely rejected; enter all fields again.CSaved, regardless of evidence.DThe field format is invalid.
Sign up free to answer and see why

Checkpoint

Why keep field errors visible after a transient toast disappears?

ATo announce the error every time an unrelated field changes.BTo keep focus trapped on the first invalid field until it passes.CTo replace the field label with the last error.DTo provide a persistent correction path that the user can revisit.
Sign up free to answer and see why

Can you design a form response that preserves the correct draft revision, gives accessible field-level recovery, and distinguishes rejection from an unknown save outcome? State the relevant identifiers, failure boundary, and evidence in your own words before selecting your confidence.

Not yetGetting thereConfident

Sources

Free to read · better with Enzo

Learn it with Enzo

Save your progress, answer the checkpoints, and let Enzo quiz you on what you just read.