ARIA Live Regions: aria-live, role=status and role=alert
How to make status messages, result counts and toasts heard by screen readers, and why a live region that looks right can stay silent.
A visitor filters a product list and the count changes from 120 items to 14. A form saves and a green "Changes saved" appears. A toast says the item is in the cart. Sighted users catch all of it out of the corner of their eye. Screen reader users hear nothing, because nothing told their software that the page changed.
ARIA live regions fix that. This guide covers what WCAG actually asks for, which of role="status", role="alert" and aria-live to use, the places sites miss most, and the one mistake that makes a correct-looking live region stay silent.
What WCAG 4.1.3 Status Messages requires
The criterion is WCAG 4.1.3 Status Messages, Level AA. It says status messages must be programmatically determinable through role or properties, so assistive technology can present them "without receiving focus".
The Understanding document narrows what counts as a status message. It is a message about:
- the success or result of an action ("Changes saved", "3 items added to cart"),
- a waiting state ("Searching..."),
- the progress of a process ("Uploading, 40% complete"),
- or the existence of errors ("2 fields need attention").
Two things are out of scope, and they save a lot of over-engineering. The search results themselves are not a status message, only the short line about them such as "18 results returned". And anything that moves focus, like opening a dialog, is a change of context, which screen readers already announce, so it does not need a live region.
role="status", role="alert" and aria-live
A live region is an element whose changes a screen reader reads out without the user going there. You create one in three common ways, and the WAI-ARIA 1.2 specification defines how the roles map to the attribute:
| Markup | Behaves like | Use it for |
|---|---|---|
role="status" |
aria-live="polite" and aria-atomic="true"
|
Results counts, saved confirmations, cart updates, most toasts |
role="alert" |
aria-live="assertive" and aria-atomic="true"
|
Errors and warnings the person must hear now |
aria-live="polite" |
Announced when the screen reader finishes what it is saying | Custom regions where you need to control aria-atomic yourself |
Polite waits for a pause. Assertive interrupts whatever the screen reader is reading. That is why MDN's live regions guide notes that normally only aria-live="polite" is used. An assertive region that fires on every keystroke makes a form unusable, and the W3C alert pattern warns that frequent interruptions hurt people with visual and cognitive disabilities.
aria-atomic="true" means "read the whole region, not just the part that changed". The Understanding document gives the example of a cart that changes from "0 items" to "3 items": if only the number is announced, the user hears "three" with no context. The roles set it to true for you.
Do not stack aria-live="assertive" on top of role="alert" for safety. MDN notes that the combination causes double speaking in VoiceOver on iOS.
The mistake that makes live regions silent
This is the bug behind most "we added aria-live and it still says nothing" tickets. Screen readers announce changes to a live region they already know about. If your script creates the element and its message in one go, there is no change to announce: the region and the text arrived together.
// Broken: the region and its text are inserted at the same moment
const msg = document.createElement("div");
msg.setAttribute("role", "status");
msg.textContent = "Changes saved";
document.body.append(msg);
<!-- Fixed: the empty region is in the page from the start -->
<div id="form-status" role="status"></div>
// Fixed: only the text changes later
document.getElementById("form-status").textContent = "Changes saved";
MDN puts it plainly: the most reliable way to make sure a live region is registered is to include it in the initial markup, start it empty, and give assistive technology time to notice it before you update it. The W3C alert pattern adds that screen readers do not announce alerts already on the page before it finishes loading, so a server-rendered error with role="alert" will not be read out on page load either. For errors after a full page submit, move focus to an error summary instead.
Frameworks make this easy to get wrong. A React or Vue component that renders {saved && <div role="status">Saved</div>} mounts the region and the text together. Render the container always, and change only what is inside it.
Five places sites miss status messages
1. Search results and filters
The results list does not need announcing, but the count does. Keep one status region near the top of the results and update its text after each search or filter change.
<!-- Broken: the count updates visually only -->
<p class="results-count">14 products</p>
<!-- Fixed: the same element, announced politely -->
<p class="results-count" role="status">14 products</p>
If filters apply on every checkbox click, a short delay before updating the text stops the screen reader reading five counts in a row.
2. Cart totals and "added to cart"
An add to cart button that updates a mini cart icon gives a screen reader user no feedback at all. Announce the whole phrase, "Blue wool scarf added to cart, 3 items", not just the new number. The Understanding document suggests adding visually hidden text such as "in shopping cart" when the visible text is too short to stand alone.
3. Inline form errors
Validation that appears as you leave a field is a status message about the existence of errors. Put the error text in an element linked to the field with aria-describedby, so it is read when the field is focused, and keep a single polite region that summarises the state, rather than an assertive alert on every field. See accessible forms for the field markup itself.
4. Toasts and snackbars
A toast container should be a status region that exists from page load, with each toast written into it. Two more problems hide here. Toasts that vanish after three seconds can disappear before a screen reader reaches them, and the W3C alert pattern cautions against alerts that disappear automatically. And a toast with an Undo button is out of reach for keyboard users if it closes before they can tab to it. Give important toasts more time or a close button, and put the Undo somewhere permanent too.
5. Loading and saving states
A spinner is a picture. "Loading results" and then "Results loaded" in a status region tell a screen reader user the page is working, and that it has finished. For long uploads, announce progress at sensible steps such as every 25%, not every percent.
How to test a live region
You can do most of the checking without a screen reader:
- View the page source (not the inspector) and confirm the region's element and its role are in the initial HTML, empty or with its starting text.
- Trigger the action and watch the element in your browser's DevTools. Only its text should change; the element itself should not be replaced.
- Check the role in the accessibility tree. Chrome, Edge and Firefox all show an element's computed role in their accessibility panels.
-
Look for typos.
aria-lveorrole="stauts"does nothing at all. The free ARIA checker flags misspelled and made-up aria- attributes on any page.
Then confirm with a real screen reader, because that is the only way to know an announcement happens. NVDA on Windows is free, and its Speech Viewer shows what it says as text, which makes the check quick even if you do not use a screen reader day to day. VoiceOver is built into macOS. How to test with a screen reader walks through a short pass.
An automated scan cannot tell you whether a message was spoken, only whether the markup around it is valid. Treat status messages as part of the manual pass of any accessibility audit.
Explaining it to a client or a manager
"When something on the page changes without a reload, like the cart count or a 'saved' message, blind customers using a screen reader are not told. We add a hidden hook that makes their software read the message out. It does not change how the page looks." That is usually all the context needed: it is a small code change with no design impact, and it maps to a named WCAG AA criterion.
Live region checklist
- List every message that appears without a page reload: counts, confirmations, errors, toasts, loading states.
- Use
role="status"for most of them androle="alert"only for errors that need attention now. - Put each region in the initial HTML and change only its text.
- Announce the whole message, not just a changed number.
- Do not add
aria-liveon top of a role that already implies it. - Keep toasts on screen long enough to be heard, and never put the only Undo inside one.
- Check the markup with the ARIA checker, then confirm the announcement with NVDA or VoiceOver.
To see what else a page gets wrong in its ARIA, run a free accessibility scan, and read when and how to use ARIA attributes for the rules that apply beyond live regions.