ARIA Live
You click "Save," and a little message flashes: "Saved!" A sighted person sees it at once. A screen reader user hears nothing, because focus never moved, and the screen reader only reads what you point it at.
That gap is what live regions fix. A live region is a part of the page that a screen reader watches. When its content changes, the change is announced, without moving focus and without the user going to look for it. Search results, form errors, "added to basket," chat messages, and countdowns all rely on this.
Live regions are powerful, and easy to get wrong. Most of the trouble comes from one detail you will learn early in this lesson: the region must already be in the page before its text changes.
What You Will Learnβ
- What a live region is, and when you need one
- The difference between polite and assertive
- The built-in live roles:
status,alert,log, andtimer - How
aria-atomic,aria-relevant, andaria-busychange what is read - Why a live region must exist before it changes
- How to write short, useful announcements
- How this meets WCAG 4.1.3 Status Messages
- How to check your live regions
The Big Ideaβ
- HTML Code
- Live Region Lab
<!-- A polite status message. It is in the page from the start, and empty -->
<div role="status" id="save-status"></div>
<!-- An urgent error. Interrupts the reader -->
<div role="alert" id="save-error"></div>
<!-- Same as role="status", written as an attribute -->
<div aria-live="polite" aria-atomic="true" id="count"></div>
<button type="button" id="save">Save recipe</button>
<script>
document.getElementById("save").addEventListener("click", () => {
// Change the text AFTER the page has loaded
document.getElementById("save-status").textContent = "Recipe saved.";
});
</script>
What was sent:
- Nothing yet. Press a button.
The box above is a real live region on this page. If you use a screen reader, switch it on and try each setting. In general, a polite region waits for the reader to finish speaking, an assertive one interrupts, and one with no attribute is silent, but exact behaviour differs between screen readers and browsers. When the box is created at the same moment as its text (untick the checkbox), many screen readers say nothing at all. This is the most common live region bug.
Try each setting. Then untick the box that says the region is already present, and press Save again. If you use a screen reader, you may notice the message disappear from the speech.
Put the live region in the HTML first. Fill it with text later. Do not create a new region and put the message into it at the same moment. Many screen readers will say nothing.
Polite or Assertive?β
aria-live takes three values:
| Value | What it does | Use it for |
|---|---|---|
off | The default. Changes are not announced | Most content |
polite | Waits until the reader has stopped speaking, then announces | Saved, search results, progress, "added to basket" |
assertive | Interrupts whatever is being spoken | Serious errors, a session about to expire |
Default to polite. An interruption in the middle of a sentence is jarring, and the user may lose their place. Reserve assertive for messages the user must hear right now. If everything is urgent, nothing is.
The Live Rolesβ
You do not always need to write aria-live yourself. Several roles come with the right behaviour.
| Role | Implied behaviour | Use it for |
|---|---|---|
status | Polite, atomic | Saved, loaded, "12 results found" |
alert | Assertive, atomic | Errors and urgent warnings |
log | Polite, not atomic | Chat, activity feeds, a growing list |
timer | Off | Countdowns and clocks, not read on every tick |
marquee | Off | Rarely used; scrolling values like a ticker |
See them in action:
- Implied aria-live: polite
- Use it for: Saved, loading finished, 12 results found. Not urgent.
These are real live roles. Note that the status, alert and log containers here are swapped in when you choose a role, so the very first message after switching may not be announced. In your own pages, keep the region in the HTML from the start. The listed live values are the defaults the ARIA specification gives each role. A few screen readers handle alerts and timers a little differently.
Which should I pick?β
- Result of an action, not urgent (saved, deleted, loaded):
role="status". - Something went wrong, or action is needed now:
role="alert". - A running list of items:
role="log". - Not sure:
role="status". It is the gentlest choice.
role="status" and aria-live="polite" behave almost the same, but the role also tells assistive technology what the region is. When a role fits, use the role. Use aria-live on its own when you only need to set the politeness, such as on a custom widget.
Make the Whole Message Make Sense: aria-atomicβ
When part of a live region changes, should the screen reader read just the changed bit, or the whole region?
aria-atomic="true": read the whole region every time.aria-atomic="false": read only the changed parts. This is the default foraria-liveon its own.
It matters when a message is made of pieces. If only the number changes in "Basket: 3 items, total 12 dollars," reading only "4" would be baffling.
A screen reader may say: Press a button.
The status box is real, but the "may say" line is a simplified simulation. With aria-atomic="true" the whole region is read, so the message makes sense. With false, a screen reader may read only the parts that changed, here just the number (the total changes too, so you may hear two numbers with no words). Real screen readers vary, so test yours.
The simplest fix is to keep the message as one piece of text and replace the whole thing. Then atomic or not does not matter.
Other Controlsβ
aria-relevantβ
aria-relevant says which kinds of change to announce. Its values are additions, removals, text, and all. The default (additions text) is right nearly always. Setting it to all makes a screen reader announce removals as well, which is usually just noise. Support also varies, so do not rely on it.
aria-busyβ
aria-busy="true" tells assistive technology: "I am still updating, please wait and read it all at the end." It is useful while a list loads in pieces.
<div id="results" role="status" aria-busy="true"></div>
<!-- ...fill it... -->
<script>
const box = document.getElementById("results");
box.textContent = "12 recipes found.";
box.setAttribute("aria-busy", "false");
</script>
Remember to set it back to false. Forget, and the region stays silent forever.
Where Live Regions Fitβ
Status messages (WCAG 4.1.3)β
WCAG 2.1 success criterion 4.1.3 (Status Messages, Level AA) says that when a message tells you the result of an action, or the state of the page, and focus does not move to it, assistive technology must be able to announce it. A live region is how. (Check the exact wording and level at w3.org before you rely on it.)
Search and filter resultsβ
When a user types in a filter and the list changes, tell them how many results there are. Do not read the whole list.
<label for="q">Search recipes</label>
<input id="q" type="search">
<p id="count" role="status"></p>
<ul id="list">...</ul>
When results change, set count to "5 recipes found." The list itself stays quiet.
Form errorsβ
Form errors need care. After a failed submit, a good pattern is to move focus to an error summary (see Focus Management). For single-field errors, link the message with aria-describedby (see aria-describedby), and you can also use role="alert" for brief, urgent ones.
Chat and feedsβ
A chat box is a classic role="log": new messages are added, and the reader hears each one. For busy chats, give users a way to pause or slow announcements.
Loading and progressβ
Announce the start ("Loading...") only if it takes a while, and the finish ("12 recipes loaded"). Avoid announcing every percent.
Toasts and snackbarsβ
A "toast" is a small message that pops up and disappears. For a screen reader, it needs role="status" (or alert), in the page before it fills, and it must stay long enough to be heard. A message that vanishes in 2 seconds can be missed by anyone, and is a problem for people who read slowly.
Writing Good Announcementsβ
- Short. "Recipe saved." is better than a paragraph.
- Clear on their own. Include the thing: "Rye bread added to basket." not just "Added."
- Plain text. No links, buttons, or lists inside. Live regions are not for things people need to operate.
- Not repeated. Setting the same text again may not be announced. If you must repeat it, clear the region, then set the text again a moment later.
- Rare. Announce outcomes, not every keystroke or hover.
- In the page language, matching the rest of the page.
What Not to Doβ
- Do not announce what focus already says. If focus moves to the new content, the screen reader reads it. A live region on top makes a double announcement.
- Do not put a live region around a big block.
aria-liveon<main>or on a long list can make a screen reader read everything on each change. - Do not hide a live region with
display: none. It then leaves the accessibility tree. (A visually hidden region, described in aria-hidden, is fine.) - Do not use
aria-live="assertive"on lots of things. It becomes an alarm that never stops. - Do not use live regions for essential, permanent instructions. Messages disappear. If the user needs it, show it as normal text, too.
- Do not make a toast the only place an important error appears. Keep the message visible until fixed.
Check Your Live Regionsβ
- HTML Code
- aria-live Checker
<!-- Things the checker looks for -->
<div class="toast">Saved!</div> <!-- no live role -->
<div aria-live="loud">Updating</div> <!-- invalid value -->
<div role="alert" aria-live="polite">Error</div> <!-- conflicting -->
<div aria-live="polite" hidden>Status</div> <!-- hidden region -->
<div aria-live="polite" aria-atomic="yes">...</div> <!-- bad atomic value -->
Run the messy sample, fix every problem, then try the fixed version.
Check it by handβ
- Turn on a screen reader (NVDA or JAWS on Windows, VoiceOver on Mac and iPhone, TalkBack on Android). Trigger each message with the keyboard.
- Listen carefully. Is the message heard once? Is it complete? Is it too early or too late?
- Try more than one screen reader and browser. Live regions are one of the less consistent areas of ARIA.
- Test the same message twice. Is it announced the second time?
- Check your page after a page load. Is the region in the HTML, empty, from the start?
- Use the browser's Accessibility panel to see which elements have a live role or
aria-live.
Good Habitsβ
- Add the region to the HTML first, empty, and update its text later.
- Use the role that fits (
status,alert,log) before writingaria-liveby hand. - Default to polite. Keep assertive for emergencies.
- Keep messages short, plain, and complete.
- Make the message visible too, for people who do not use a screen reader.
- Use one region for many messages instead of creating a new one each time.
- Do not combine live regions with focus changes for the same message.
- Test with real screen readers.
Accessibility Checklistβ
- Every important status message has a live region (
status,alert, oraria-live) - The live region is in the HTML before it is filled
- Polite is the default, and assertive is rare
- Messages are short, complete, and plain text
- No links or buttons inside live regions
- Live regions are not hidden with
display: noneorhidden - Toasts stay on screen long enough, and can be dismissed
- The same message is not also announced by a focus move
- Important errors stay visible until fixed
- Tested with at least one real screen reader
Security and Privacy Notesβ
- Announcements are spoken aloud. A live region can read out text in a public place, on a speaker, or in a screen-sharing call. Do not announce passwords, card numbers, health details, or other private information.
- Never put untrusted text into a live region with
innerHTML. If the message includes user input (a username in a chat), usetextContentso a script cannot be injected. - Do not let messages from other users flood a region. A chat or notification feed that anyone can post to can be used to drown out or distract a screen reader user. Limit and filter it.
- Do not use announcements to mislead. A message that says "Payment confirmed" must be true, and must match what is on screen.
Global Audience Notesβ
- Announcements are read in the page language (the
langattribute), or in the user's screen reader voice. Setlangcorrectly, and mark foreign words with their ownlang. - Translate your messages, and keep them short. Auto-translation may change the wording, so avoid depending on exact phrases.
- Numbers, dates, and currencies should follow the user's local format, so they are read correctly.
- Right-to-left languages: live regions work the same, but check that mixed text (numbers inside Arabic or Hebrew) reads in the right order.
- Slow connections: announce "Loading" early, and the result when it finishes, so the user is not left in silence. But do not announce every step.
- Screen readers differ by country and device. Free options like NVDA and TalkBack are widely used worldwide. Test with the tools your readers have.
Common Mistakes to Avoidβ
- Creating the live region and its text at the same time. The most common bug.
- Using
display: noneorhiddenon the region. - Making everything
assertive. - Putting
aria-liveon a huge container, like the whole main area. role="alert"witharia-live="polite", which contradicts itself.- Messages that are too long, or have links or buttons in them.
- Toasts that disappear in a couple of seconds.
- Announcing the same thing with focus and a live region.
- Forgetting
aria-busy="false". - Repeating the same text and expecting it to be read again.
- No visible version of the message for people who do not use a screen reader.
- Never testing with a screen reader.
Practice Timeβ
Try these in your browser and your editor:
- Use the live region lab with each setting. If you can, listen with a screen reader.
- Untick "already in the page," and compare it with the ticked version.
- In the atomic lab, switch
aria-atomicon and off, and explain why it matters. - Use the live types lab. For each role, say when you would use it.
- Run the checker on the messy HTML, fix every problem, and run it again.
- Add a "Saved" message to a form in a page you built, using
role="status". - Add a result count to a filterable list.
- Turn an existing toast into one that works for a screen reader, and stays long enough.
- Make a chat box with
role="log". - Bonus: build a countdown that only announces at one minute, ten seconds, and zero.
Quick Recapβ
Click a question to check your answer.
1. What is a live region?
A part of the page that a screen reader watches. When its content changes, the change is announced without moving focus.
2. What is the difference between polite and assertive?
Polite waits until the screen reader has finished speaking. Assertive interrupts. Use polite by default, and assertive only for urgent messages.
3. Which role would you use for "Recipe saved"?
role="status". It is polite and atomic, and fits results that are not urgent. Use role="alert" for serious errors.
4. Why must the live region exist before its text changes?
Screen readers watch for changes inside a region they already know about. A region created together with its text is often not announced at all.
5. What does aria-atomic="true" do?
It makes the screen reader read the whole region each time, instead of only the part that changed, so the message makes sense.
6. Which WCAG criterion covers status messages?
4.1.3 Status Messages (Level AA in WCAG 2.1). Messages that report results or state, without taking focus, must be announced by assistive technology.
Key Takeawaysβ
- A live region announces changes without moving focus.
- Put the region in the page first, empty, then update its text later.
- Default to
polite. Useassertiveorrole="alert"rarely. - Use the roles
status,alert,log, andtimerwhere they fit. - Keep messages short, plain, and complete, and show them on screen too.
- Do not hide live regions with
display: none, or wrap big blocks in them. - Do not announce secrets, and use
textContentfor any user text. - Test with real screen readers. Behaviour varies.
Next, learn how to test everything you have built in this section, in Accessibility Testing.