Accessibility
aria-live for form errors
A form error is announced by a live region already in the DOM plus aria-invalid on the field. WCAG 4.1.3 Status Messages, level AA, requires it.
Key points
- The live region must exist before the error: if you create it with the text, the announcement may never fire.
- role="alert" is equivalent to aria-live="assertive"; use it for the submit summary, not for every keystroke.
- Tie the message to the field with aria-describedby and mark the field with aria-invalid="true".
An accessible form error is announced by a live region that was already in the DOM, while the field gets aria-invalid="true" and an aria-describedby pointing at the message. Criterion 4.1.3 Status Messages, level AA, requires the message to be announced without moving focus.
The markup
Email
Create account
Two regions with different jobs. aria-live="polite" on the field announces the error while the user finishes the rest of the form. role="alert" on the submit summary interrupts and reports how many fields to fix; it implies aria-live="assertive" and aria-atomic="true".
Why the region must exist first
Assistive technology observes nodes that already carry a live role. If the container is created at the same moment as the text, the observer may miss it and the announcement never happens. The fix is to leave the container empty in the markup and change only textContent. Some readers announce an inserted node too, but behaviour varies with browser and version.
Error and field state
Criterion 3.3.1 Error Identification, level A, requires the error to be described in text, not by colour alone. aria-invalid="true" reports the state to the reader; aria-describedby ties the message to the field, so the user hears it again when returning to the input. Criterion 3.3.3 Error Suggestion, level AA, requires a possible fix: “Add an address with an at sign”, not “Invalid value”.
The test that counts
Fill the form with an error and submit without looking at the screen. With NVDA or VoiceOver you must hear the message once, without focus jumping elsewhere. Then go back to the field with Shift+Tab: the message must be read again through aria-describedby.
npx --yes @axe-core/cli https://example.com
axe-core is open source under the MPL-2.0 licence. It finds fields with no name and invalid attributes, not the order of announcements: a live region mounted late passes the test and stays silent.
The EneUI catalogue
EneUI indexes form validation, the fields and the Cult UI popover form record, with an MIT licence declared upstream: a form inside a panel, the case where the live region must live in the node that stays mounted. Checked on 1 November 2026 against 111,985 components.
The limitation
A live region announces the change, it does not explain it. If the user is in browse mode and focus is not on the form, the announcement can arrive without context: you also need a summary with links to the fields. And no attribute replaces server-side validation, which stays mandatory.
Where to continue
The operational checklist is in accessible React components; the map of roles is in what ARIA is. The comparison of headless primitives is in Radix, Base UI and React Aria.
Frequently asked questions
role alert or aria-live polite?
It depends on urgency. role="alert" interrupts the current reading and suits the submit summary; aria-live="polite" waits for a pause and suits a single field error.
Can I create the message together with the container?
Better not. The region must exist in the DOM before the error, otherwise some readers miss the change. Leave the container empty and update only the text.
Is aria-invalid needed on the field?
Yes. It reports the field state to the screen reader and must go back to false once the error is fixed. On its own it is not enough: the message also needs aria-describedby.
Should the message move focus?
No, the announcement happens without moving focus. Move it to the summary only after a failed submit, if the form is long, and offer links to each field.
Does axe find missing live regions?
Only in part. axe reports invalid roles and attributes, but it cannot know whether the announcement happened. The proof stays a listening test with NVDA or VoiceOver.