When a page changes without a reload, sighted users see it: a "Saved" message appears, a basket count goes up, search results update. Screen reader users only hear what is under their focus, so they miss these changes. A live region tells assistive technology to announce new content in a part of the page, without moving focus.
4.1.3 Status Messages
Success criterion 4.1.3 Status Messages (AA) requires that status messages can be announced by assistive technology without receiving focus. A status message is a change in content that tells the user about the result of an action, the progress of a process or an error, without changing context.
Examples:
- "Your changes have been saved."
- "12 results found."
- "3 items in your basket."
- "Uploading: 60%."
- "Could not connect. Trying again."
The live region roles and attributes
| Markup | Politeness | Use for |
|---|---|---|
role="status" | Polite (aria-live="polite", aria-atomic="true" implied) | Results, confirmations, progress |
role="alert" | Assertive (aria-live="assertive", aria-atomic="true" implied) | Urgent, time-sensitive problems |
role="log" | Polite | Chat messages, activity feeds, where new items are added |
aria-live="polite" | Polite | Any region, when no role fits |
aria-live="assertive" | Assertive | Rarely; prefer role="alert" |
- Polite waits until the screen reader finishes what it is saying.
- Assertive may interrupt the current speech. Use it only for information the user needs immediately, because interruptions are disorienting and can cut off other content.
Related attributes:
aria-atomic="true"announces the whole region when part of it changes, not just the changed part. Use it when the update only makes sense in full, such as "3 items in your basket".aria-relevantcontrols which kinds of change are announced. The default, additions and text changes, is almost always right. Leave it alone.
The rule that matters most: the region must exist first
Screen readers watch live regions that are already in the accessibility tree. If you insert an element with role="status" and its text at the same moment, many screen readers announce nothing.
<!-- In the HTML from the start, empty -->
<p id="save-status" role="status"></p>
// Later, change only its content
document.getElementById('save-status').textContent = 'Draft saved at 14:32.';
role="alert" is the partial exception: many screen readers announce an alert element that is added to the page. Even so, adding the container when the page loads and changing its content is the most reliable approach for every role.
Do not toggle a live region with display: none or the hidden attribute in the same step as you change its text. Hidden regions are removed from the accessibility tree, so when they reappear they are new again. Keep the region present and empty instead.
Example: search results count
<search>
<form id="book-search">
<label for="q">Search books</label>
<input id="q" name="q" type="search">
<button type="submit">Search</button>
</form>
</search>
<p id="results-status" role="status"></p>
<ul id="results"></ul>
<script>
const books = ['Brick Lane', 'Small Island', 'The Remains of the Day', 'White Teeth', 'Wolf Hall'];
const form = document.getElementById('book-search');
const status = document.getElementById('results-status');
const results = document.getElementById('results');
form.addEventListener('submit', (event) => {
event.preventDefault();
const query = form.q.value.trim().toLowerCase();
const matches = books.filter((title) => title.toLowerCase().includes(query));
results.replaceChildren(
...matches.map((title) => {
const li = document.createElement('li');
li.textContent = title;
return li;
})
);
status.textContent = matches.length === 1
? '1 result found.'
: `${matches.length} results found.`;
});
</script>
Focus stays in the search field, so the user can refine the search. The status announces the count politely. The results list is not a live region: announcing every title would be overwhelming. Users can move to the list when they are ready.
For search-as-you-type, wait until the user pauses before updating the status, for example 500 milliseconds after the last keystroke. Otherwise each keystroke queues another announcement.
Example: announcing the same message twice
If the text of a region does not change, nothing is announced. When a user saves twice and both messages are "Saved", clear the region first and set the text after a short delay.
function announce(region, message) {
region.textContent = '';
setTimeout(() => {
region.textContent = message;
}, 100);
}
announce(document.getElementById('save-status'), 'Draft saved.');
Example: an error that needs immediate attention
<div id="connection-alert" role="alert"></div>
<script>
function showConnectionError() {
document.getElementById('connection-alert').textContent =
'Connection lost. Your changes will be saved when you are back online.';
}
window.addEventListener('offline', showConnectionError);
</script>
Use role="alert" sparingly. Form validation errors after submission are usually better handled by moving focus to an error summary (lesson 9), because users need to go and fix them, not just hear about them.
Live regions or moving focus?
| Situation | Better approach |
|---|---|
| The user should keep working where they are | Live region |
| The update is a short confirmation or count | Live region |
| The user must act on new content next | Move focus to it |
| A dialog or new view opens | Move focus into it |
| A form submission failed | Move focus to the error summary |
Sometimes you do both: move focus to a new section heading and let a status message confirm what happened.
Writing good announcements
- Be short and specific: "Added to basket" rather than "Success!".
- Put the important part first: "3 results found for 'garden'".
- Do not repeat information the user will hear anyway when focus moves.
- Do not announce constantly. Updating a live clock or a progress bar every second floods the speech queue. Announce milestones such as 25%, 50% and 75% instead.
- Keep the message visible where possible. Sighted users benefit from it too, and so do people who use magnifiers or have cognitive disabilities.
Testing live regions
- Turn on NVDA or VoiceOver and perform the action with the keyboard.
- Listen: is the message announced once, at the right time, without interrupting more important speech?
- Repeat the action. Is the second message announced too?
- Test in at least two screen reader and browser combinations, because support details differ.
Summary
- 4.1.3 Status Messages requires updates to be announced without moving focus.
- Use
role="status"for most messages androle="alert"only for urgent ones. - Put the live region in the page first, empty, then change its text.
- Do not hide and show live regions to trigger announcements; clear and reset text to repeat a message.
- Keep announcements short, specific and infrequent.
- Move focus instead when the user needs to act on the new content.