Lesson · Beginner

Form labels, errors, and recovery

Help people understand, complete, validate, and recover from forms with persistent instructions and programmatic errors.

Published
Last checked

Errors need identity and location

State what happened, how to fix it, and which field is affected. Associate the message with the control and summarize errors near the form heading when several fields fail.

<label for="start-date">Start date</label>
<p id="start-date-help">Use the format YYYY-MM-DD.</p>
<input
  id="start-date"
  name="start-date"
  aria-describedby="start-date-help start-date-error"
  aria-invalid="true"
/>
<p id="start-date-error">Enter a date on or after 2026-08-01.</p>

Only set aria-invalid when the value is known to be invalid. Do not announce errors before a person has a reasonable chance to complete the field.

Recovery is part of success

Keep safe values after validation fails. Move focus to an error summary or announce the status without unexpectedly taking control away. Server validation remains required even when client validation exists.

How browsers and assistive technology behave

A visible label and its control become one programmatic relationship when the label's for value matches the control's id. aria-describedby adds instructions or an error to that control's description; it does not replace the label. Browser constraint validation can stop submission for fields such as required or type="email", but the wording, focus behavior, and exposure of native messages vary. Treat that validation as a helpful baseline, not the entire recovery design.

When a server rejects a submission, it returns a new page or response. The browser cannot automatically infer which visible sentence is an error, which field it belongs to, or whether previously entered values should be restored. The application must make those relationships explicit and must never echo unsafe input into executable markup.

Decisions and trade-offs

Validate on blur only when early feedback genuinely helps and does not punish unfinished input. Validating every keystroke creates noise, particularly for screen-reader users who hear changing status. Submission-time validation is predictable; a careful hybrid can work for formats that are unambiguous.

Use an error summary when several controls fail. Give it a heading, link each message to the corresponding control, and focus the summary after a failed submission. For one inline error, an announced status may be sufficient. Do not clear passwords, payment data, or other sensitive fields merely to simplify state management, but do avoid retaining secrets longer than the task requires.

Accessibility consequences

Color alone does not identify an invalid value. Pair the visual treatment with text that names the problem and gives a correction. Keep instructions visible; placeholder text disappears while typing and is not a reliable label. Required fields need a communicated requirement before submission, not only a red asterisk whose meaning is explained afterward.

Focus should move only when that move helps recovery. After a failed multi-field submission, focus the summary. After an asynchronous check, announce the result without dragging focus away from the field being edited. After success, place confirmation where it will be encountered and do not claim success until the server has accepted the data.

Common failures and fixes

  • The error is visible but not announced. The message is ordinary nearby text with no relationship to the field. Reference its stable id from aria-describedby, and use a restrained live region for asynchronous status.
  • A field is marked invalid before interaction. Validation ran on initial render. Delay the invalid state until submission or an appropriate completed interaction.
  • Correct values disappear after one mistake. The response rebuilds a blank form. Re-populate fields that are safe to retain and let the person correct only what failed.
  • The form says “sent” but nothing was delivered. A client animation is standing in for an endpoint result. Bind confirmation to a verified successful response and provide an honest retry path.

Verify it

Submit an empty form, then a badly formatted value, then a server-rejected value. Complete the sequence with Tab, Shift+Tab, Enter, and Space. Inspect each control in the browser accessibility tree and confirm its name, description, required state, and invalid state. At 320 CSS pixels and 200% text zoom, check that labels, messages, and the summary reflow without hiding the submit action. Finally, reload the failed response and confirm safe values remain while no secret appears in the URL, page source, analytics event, or log.

Exercise and next step

Submit a form with three mistakes using a keyboard and a screen reader. Confirm you can find each error, correct it, and submit without re-entering valid data. Then compare the result with the production form-handling checklist in the related HTML forms lesson before connecting the form to a real endpoint.

Free template + launch checklist

Build a page you can check before launch

Start with one reviewed semantic HTML page, then work through the one-page checklist against your published URL.

Check your inbox and confirm before the download arrives. No account required. We do not track email opens. See the privacy notice.