The problem
You add a door to the quote and a small message appears: "Added — 3 doors in the quote". A sighted user sees it in the corner of their eye. A screen reader user is told nothing at all: focus has not moved, nothing they are reading has changed, and the page does not narrate itself.
A live region is the instruction to announce a change without moving focus. It is the right answer for toasts, form-validation summaries, search-result counts, "saved" indicators and progress.
The two you need
Assertive interrupts whatever is being read, mid-word. Use it for errors and almost nothing else; a page full of assertive regions is unusable.
<p role="status"></p> <!-- polite: waits until the user pauses. aria-live="polite" -->
<p role="alert"></p> <!-- assertive: interrupts. aria-live="assertive" -->
| Role | Politeness | Use for |
|---|---|---|
status | polite | saved, added, "4 results" — the normal case |
alert | assertive | errors and anything the user must hear now |
log | polite | a chat or a console, where order matters |
progressbar | — | a value, not an announcement |
The rule people fall over
Assistive technology watches live regions for changes. A region that appears already containing text is not a change to anything — it is a new element, and it is usually missed. Render the empty container with the page, then write into it.
// nothing is announced: the region and its content arrive together
document.body.insertAdjacentHTML("beforeend", '<p role="status">Added</p>');
// announced: the empty region was there, and its text changed
document.querySelector("#status").textContent = "Added — 3 doors in the quote";
A live region on a list that updates while typing narrates every keystroke. Debounce it, announce the result rather than the process ("4 doors found"), and never put one on a clock.
The attributes around it
aria-atomic="true" is usually what you want for a short sentence: without it, changing "3 doors" to "4 doors" may announce only "4". aria-relevant exists and is almost never needed.
<div id="status" role="status" aria-live="polite" aria-atomic="true">
<!-- atomic: read the whole region, not only the bit that changed -->
</div>
<div aria-busy="true">…</div> <!-- "still loading, do not announce yet" -->
When a live region is the wrong tool
- A dialog — that takes focus instead.
- A route change — move focus to the new heading, as in the Focus lesson.
- An error on a field — attach it with
aria-describedbyand focus the field; a live region as well is usually too much. - Anything the user did not cause. An announcement with no context is worse than silence.