Deep dive: understanding live regions
Posted:
Live regions can be one of the more confusing areas of accessibility. On the surface, they seem simple enough, but in day-to-day practice, live regions can be inconsistent and often cause confusion for developers implementing them. In this deep dive, I’ll explore the basics, some nuanced aspects, and the common problems and questions that crop up around live regions.
What are live regions?
Live regions are specific parts of a web page that update dynamically in response to user actions or external events. Since they typically update outside the user's area of focus, screen readers will, in most cases, announce content changes to the live region, without requiring keyboard focus changes or page reloads. You can think of them as a notification system for screen readers.
When a browser finds a live region on a page, it exposes that information through the accessibility tree. If the content inside the live region changes, the browser sends events through the accessibility API. Screen readers listen for those events and announce the updated content to the user.
Why use live regions
Modern websites and applications often update content dynamically, without a page reload. That’s fine visually, but it can leave screen reader users unaware of changes outside their current area of focus. Screen readers only announce what the user is currently interacting with. Updates triggered elsewhere on the page may go unnoticed, leaving the user without feedback.
There are two ways to make a screen reader announce content outside of typical navigation:
- Move keyboard focus to the changed content.
- Use a live region.
In many cases, we wouldn’t want to shift focus to new content, as this could be disorienting. Live regions provide a way to notify users of these changes without requiring keyboard focus to be moved.
A common example is on an e-commerce site. You press a button to add an item to your basket, and a status message appears confirming the item was added. A sighted user would be able to see that message. A screen reader user, still focused on the button, won’t hear anything unless that message is exposed properly. That could leave them having to navigate to the basket just to confirm the action worked. That’s not only time-consuming but also inconvenient and reduces confidence when using the site.
When to use live regions
Live regions are useful when important content updates dynamically without moving keyboard focus.
They aren’t needed when:
- The content already receives keyboard focus.
- Content is available on page load.
- State can be communicated through existing ARIA attributes. For example, a disclosure button that expands content should use
aria-expanded, not a live region. - The update is purely decorative or not important enough to announce.
Depending on the scenario, a live region may be required to meet WCAG 4.1.3 Status Messages (Level AA).
Creating live regions
There are three ways to create live regions.
Using aria-live
Adding the aria-live attribute to an element explicitly designates it as a live region. It does not change the element’s semantics, which is useful if you need to maintain the element's existing semantics. The chosen value (politeness setting) determines the update's priority. There are three aria-live values:
assertive: indicates updates to the region are high priority and should be announced immediately, interrupting any current output. Because of this, assertive should be used only for critical, time-sensitive announcements.polite: indicates that updates to the region should be presented at the next opportunity, after the current output has been spoken or when the user stops typing.off: effectively disables the live region, so changes to the text will not be announced.
Using a live region role
There are five live region roles with implicit semantics that indicate content may update dynamically.
role="alert": Used to convey critical alerts. Has an implicitaria-livevalue ofassertiveand therefore should only be used for critical information, as it will interrupt the current screen reader output. Some screen readers, like NVDA, will start the announcement with "alert".role="status": Used to convey status messages - advisory information, not critical enough to justify interrupting the user / current output. Has an implicitaria-livevalue ofpolite.role="log": Used to convey a live region where new information is added in a meaningful order, and older information might disappear, like chat or messaging logs. Has an implicitaria-livevalue ofpolite.
While the following are technically live regions, they behave slightly differently. Although they indicate that content may change, they have an implicit aria-live="off" value, so updates are not announced automatically.
role="marquee": defines an area that presents non-essential information that changes frequently, like an advertising banner.role="timer": defines a numerical counter that counts up or down.
Labelling live region roles
Live region roles also support accessible names, whereas if you use aria-live to designate a live region, the semantics of the element used will dictate if it supports the addition of an accessible name.
Generic container elements like <div> and <span> do not support accessible names, so adding an aria-label or aria-labelledby would be invalid:
<!-- This is invalid -->
<div aria-live="polite" aria-label="Basket"></div>
However, as live region roles provide support for accessible names, you can do things like:
<!-- This is valid, though screen reader support differs -->
<div role="status" aria-label="Basket"></div>
In the above example, if the text "1 item added" is inserted into the live region, screen readers should announce the accessible name with the inserted text, for example, "Basket 1 item added". Keep in mind that not all screen reader and browser combinations include the accessible name in the announcement.
Using the output element
There’s a third option, the <output> element, which has the implicit role of status, though its use case is a little different - it’s meant to convey the results of a calculation or user action. At the time of writing, screen reader support isn’t as mature as aria-live or live region roles, so personally, I’d leave this option for now.
Configuration options
The following attributes can be used to configure and fine-tune a live region's behaviour.
| Attribute | Purpose | Allowed values | Default values | Implicit values on live region roles |
|---|---|---|---|---|
aria-atomic |
Controls whether the whole live region is announced, or only the changed part | true, false |
false |
role="alert": true
role="status": true
|
aria-relevant |
Controls which types of DOM changes should be treated as relevant updates for announcement | Space-separated list of: additions, removals, text, all |
additions text |
None |
aria-busy |
Indicates that updates are still being processed and announcements should wait until complete | true, false |
false |
None |
When using these options, test across a range of browser and screen reader combinations to make sure they work as expected. In my experience, aria-relevant="removals" produces inconsistent results and is best avoided.
A more reliable approach is to announce the change through a standard live region instead. For example, if you need to notify users that someone has left a chat, you could add a message such as "James has left the chat" to an existing <div role="status"></div>.
Use the correct politeness
Using the right politeness setting is critical to avoid interrupting screen reader users unnecessarily:
- For important messages: use assertive live regions, those that use
aria-live="assertive"or have an implicitaria-livevalue ofassertive, likerole="alert". - For status related messages: use polite live regions, those that use
aria-live="polite"or a role with an implicitaria-livevalue ofpolite.
| Use case | Announcement | Politeness setting |
|---|---|---|
| Form validation appearing as focus leaves a form field | "Error, enter your name" | assertive |
| The user is about to be signed out | "You are about to be signed out, press spacebar to stay signed in for another 10 minutes" | assertive |
| Applying a search results filter | Results filtered by type | polite |
| Confirming an action, like adding an item to a shopping basket | "1 Item added to basket, total items 3" | polite |
| Web chat messages | "Advisor said: Hello, how can I help?" | polite |
| Microinteractions with background processes | "Saving changes", "Changes saved" | polite |
Add to the DOM before use
For a live region to work, it must be in the DOM before it is populated with text. Inserting a populated live region into the DOM will not trigger an announcement, with the exception of role="alert". A good idea is to have the empty live region present on page load, or, in heavily JavaScript-driven applications, in the DOM as early as possible, before it’s populated with text.
Example: live region present on page load, then JS adds text
<!-- Present on page load -->
<div role="status" id="notification"></div>
<!-- Text added by JavaScript -->
<script>
const liveRegion = document.getElementById('notification');
liveRegion.textContent = 'Hello there';
</script>
<div role="status" id="notification">Hello there</div>
Example: live region added by JavaScript, with text added after a short delay
// Create the live region
const status = document.createElement('div');
status.setAttribute('role', 'status');
// Add it to the DOM
document.body.appendChild(status);
// Add text after a slight delay
setTimeout(() => {
status.textContent = 'Hello there';
}, 150);
A note on role="alert"
role="alert" technically can be inserted, prepopulated with text into the DOM, and fire the announcement, though to keep things consistent and avoid any potential issues, I’d treat this the same as other live regions, and insert it into the DOM before populating it with text (with a slight delay between the DOM insertion and the insertion of text).
Visibility
Depending on the use case, you may want a live region to be visibly displayed (if the notification is relevant to all users) or visually hidden (if it’s specifically aimed at screen reader users).
If the live region is visually hidden, it must be hidden in a screen reader-friendly way, e.g., using the CSS clip method, which typically looks like this:
.visually-hidden {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
Hiding the live region with display: none, visibility: hidden, or aria-hidden="true" will remove the live region from the accessibility tree and result in updates to it not being announced by screen readers.
WCAG considerations
4.1.3 Status Messages sets requirements and definitions around status messages. The goal of 4.1.3 is to make users aware of important changes in content by letting assistive technology notify users about status changes or messages that don’t take focus.
It defines status messages as:
change in content that is not a change of context, and that provides information to the user on the success or results of an action, on the waiting state of an application, on the progress of a process, or on the existence of errors
The understanding status messages page states:
This success criterion specifically addresses scenarios where new content is added to the page without changing the user's context. Changes of context, by their nature, interrupt the user by taking focus. They are already surfaced by assistive technologies, and so have already met the goal to alert the user to new content. As such, messages that involve changes of context do not need to be considered and are not within the scope of this success criterion.
So when a status message doesn’t have focus set to it or causes other changes of context, like a page reload, we need to use live regions with the correct roles and properties to communicate that message to screen readers. Not using live regions to programmatically communicate status messages and using assertive live region for content that is not important or time-sensitive are both examples of 4.1.3 failures.
Common mistakes
Inserting a prepopulated live region into the DOM
As covered above, with the exception of role="alert", adding a prepopulated live region to the DOM will not trigger a screen reader announcement. Have the live region present in the DOM before populating it with text.
Hiding the live region from assistive technology
A live region hidden from the accessibility tree through the use of the following will not announce updates:
display: none,visibility: hidden,aria-hidden="true",inert
There are cases where a visually hidden, but screen reader accessible, live region can be useful. In these cases, hide it using the CSS clip method.
Overusing live regions
Not everything needs to be announced. Only informative, helpful, or critical, dynamic information that might otherwise be missed. You shouldn’t use a live region to announce:
- Adverts and sales offers.
- Information already conveyed by static elements on the page, like a
<h1>. - Element state properties, e.g., a disclosure button that expands a section, should use
aria-expanded, not a live region.
Too many live regions
Having too many live regions firing on the page can be overwhelming and defeat the purpose. When multiple live regions are needed, it’s a good idea to limit their number and use JavaScript to queue and update them as needed.
Overusing assertive regions
Assertive live regions, those that use aria-live="assertive" and role="alert", will interrupt the user and could be disorienting if they are midway through a task. Use sparingly and only for critical information.
Announcing too much
Don’t insert large amounts of text into a live region; this can be hard to follow and annoying for users. Use live regions to convey short informative messages that screen reader users may otherwise miss.
Inserting duplicate text without clearing
Inserting the same text repeatedly into a live region will not cause it to be announced. If you need the same text announced again, empty the live region first, then reinsert the text after a slight delay. I’ve found 150ms seems to be the shortest delay that consistently works well.
Inserting non-text content and interactive elements
Screen readers only announce text content changes inside live regions. The semantics of inserted non-text elements will not be announced. For example:
- Image alt text is announced, but the presence of the image isn’t
- Input label text is announced, but the presence of the input isn’t
- Link/button text is announced, but the presence of the link/button isn’t
I’d advise against adding rich elements to a live region for this reason. In a small number of situations, it can be useful to inform screen reader users that non-text elements have been added, for example, in a web chat where an advisor sends a response that includes a button or link. In these cases, you could append a visually hidden notification about the elements, for example:
<div role="log">
Advisor: What can I help you with today?
<span class="sr-only">Advisor sent 2 buttons</span>
<button>Recent order</button>
<button>Returns</button>
</div>
Which would sound something like: "Advisor: What can I help you with today? Advisor sent 2 buttons. Recent order. Returns."
Placing live regions inside interactive elements
Live regions placed within interactive elements, such as buttons, may not function as expected. Instead, use a separate single live region for communicating things like button microinteractions - saving, still saving, saved, etc.
Inserting text in pieces
Don’t use multiple DOM insertions to update a single live region message. If you do, screen readers may make multiple announcements, one part at a time. Build the complete message, then insert.
Common questions
Can live regions be visually hidden?
Yes, by using a screen reader friendly hide method, such as the CSS clip method.
Do live regions need to gain keyboard focus?
No. Live regions are used to announce changes when the new content does not receive keyboard focus (since setting keyboard focus to an element typically causes it to be announced).
Is role="region" a live region?
No, role="region" is an ARIA landmark role, which should be used sparingly to designate a generic page landmark of significance to aid in screen reader navigation. It does not relate to dynamic content, nor will a screen reader announce content changes to it, like a live region.
Should I use role="timer" with aria-live="polite" to announce a countdown?
No, this would announce every timer update, which, if the timer changes every second, would quickly become frustrating for screen reader users. Generally, it’s better to use a separate live region to announce key intervals as the timer gets closer to expiring, such as 20 minutes, 15 minutes, 10 minutes, 5 minutes, 3 minutes, 2 minutes, 1 minute, 30 seconds, 15 seconds, 10 seconds, and 5 seconds.
I have a visible "callout" message, displayed on page load, should this use role="alert"?
Websites often display important messages at the top of the page that aren't triggered by user action, such as delivery delay notices or holiday opening times.
Some design systems refer to these callouts as "alerts", which can cause confusion. Although they may look like alerts visually, they do not usually need to be coded as live regions. If they are marked up properly with headings, as landmarks (potentially, depending on the use case), and a clear content structure, screen reader users can discover them as normal.
Using role="alert" in these cases can be unnecessarily disruptive, as the message will be announced immediately when the page loads.
Why are my live region updates being announced twice?
While it depends on the scenario and browser/screen reader combination, some common causes include:
- Using
role="alert"andaria-live="assertive"on the same element - Browser/screen-reader combination quirks: for example, VoiceOver/Safari will announce live region updates twice when the live region is within an iframe.
Should I use a live region to announce route changes in a Single Page Application (SPA)?
Many frameworks, like Next.js, include a dedicated live region for route change announcements. If you are rolling your own, make sure the announcement is aligned with the page’s document.title and <h1>.
Conclusion
Live regions are a powerful way to make screen reader users aware of dynamic content changes. They can also be tricky and don’t always behave as expected.
When implementing them:
- Ask yourself if a live region is needed at all.
- Use them only for short, informative messages that screen reader users may otherwise miss.
- Remember that live regions need to exist in the DOM before being populated with text, with the exception of
role="alert". - Test across different browser and screen readers combinations, and ideally with native screen reader users.
- And as always, No ARIA is better than bad ARIA.
