Start with a form people can understand before errors appear
Validation works best when each field already has a visible label, clear instructions, and an appropriate input type. A required email field, for example, should have a label that says what address is needed. If there is a format hint, place it near the field and associate it with the input. Do not rely on placeholder text as the only instruction: it may disappear as soon as someone starts typing.
For a reproducible example, imagine a browser form built with ordinary HTML controls and a small amount of vanilla JavaScript. It has an email input with the identifier email and a hint with the identifier email-hint. Before any error occurs, the input’s aria-describedby value is email-hint. The form also has a submit button. This approach does not require a framework; in a component-based interface, the same identifiers and relationships still need to reach the rendered controls.
Give each error a stable connection to its field
When validation finds a problem, add a visible message beside the relevant field. Give the email message a stable identifier such as email-error, then set the input’s aria-describedby value to email-hint email-error. A screen reader can then encounter both the original hint and the current error when the field receives focus. Set aria-invalid to true while the field has an error. A red border alone is not enough to explain what went wrong.
Write a message that helps someone act: “Enter an email address” for an empty field, or “Enter an email address in the expected format” when the browser reports a type mismatch. An email input’s built-in format check is useful, but it cannot establish whether an address belongs to someone or can receive mail. Avoid presenting that check as proof that an address is valid.
When the person corrects the field, remove the outdated error message and its identifier from aria-describedby, and remove aria-invalid or set it to false. Keep the hint association intact. In JavaScript, treat the displayed error, described-by identifiers, and invalid state as one update; changing only the text can leave assistive technology reporting an error that no longer applies.
Make submission errors easy to find
On submit, check all relevant fields rather than stopping at the first failure. For custom validation in this example, disable the browser’s automatic validation interface on the form, prevent submission in the submit handler, and inspect the field values and constraints yourself. This gives the page one consistent place to display messages. If the form is valid, continue with its intended submission path rather than calling the same submit handler again without a guard.
If several fields need attention, show a short error summary before the form. Include a link for each error that points to its field, and use wording consistent with the message beside that field. After an unsuccessful submit, move keyboard focus to the summary so the result is noticeable. The person can then choose which field to fix. Make the summary programmatically focusable if necessary, but do not leave it in the normal Tab sequence merely to support this focus move.
Avoid moving focus on every keystroke or whenever an error message changes. People need to stay in control while editing. You can recheck a field after a change or when it loses focus, but choose a predictable rule and do not announce the same error repeatedly. If validation depends on a delayed server response, make the pending state understandable and ensure any returned error is connected to the right field.
Preserve values while people make corrections
An error should not erase work. Keep the entered values in their controls after a failed submit, including values in fields that passed validation. Do not reset the form as part of displaying errors. If an interface re-renders the form, its state must retain the values; replacing an input with a blank one can make correction needlessly difficult.
Be careful with automatic cleanup. Trimming accidental surrounding spaces may be appropriate for some fields, but silently rewriting names, addresses, or free-form answers can change what a person meant. If a value needs a particular form, explain the requirement and let the person edit it. Password fields need special consideration because retaining them after a failed submission involves security and usability choices; do not apply a blanket rule to every kind of form.
Test the complete correction path
Test the example in a browser using only the keyboard: submit it empty, follow each summary link, correct one field, and submit again. Confirm that focus moves to the summary after the failed submit, links reach the intended controls, corrected fields lose their stale errors, and previously entered values remain. Then try a screen reader with the browser you are testing and listen for the label, hint, and error when an invalid field receives focus.
Also check the experience without relying on color, at a narrow viewport, and after an error message becomes longer than expected. The goal is not merely to pass a validation check. A person should be able to understand the problem, find the affected field, fix it, and finish the form without repeating work.



