Skip to content
Accessibility & inclusive designLesson 5 of 7Intermediate14 min

Live regions

When content changes without a page load, a screen reader only knows if you tell it. Learn aria-live, polite vs assertive, and the rules that make it work.

Kept on this device only.

In one line: A live region is a part of the page a screen reader watches, so when your JavaScript changes its text — a toast, a validation error, a cart count — the new words are spoken without moving focus or reloading the page.

What it is

A live region is an element you mark with aria-live (or a role that implies it). Once marked, the browser's accessibility layer watches that element, and whenever its text content changes, the screen reader announces the new content out loud. The user's focus never moves; they hear the update wherever they happen to be.

The point is that screen readers normally announce what the user navigates to. A region the user is not focused on — a status bar, a notification corner, a results count — changes silently as far as assistive tech is concerned. A live region is how you say: watch this spot, and read changes aloud as they happen.

Why it matters

Modern UIs change without a page load constantly: a toast confirms a save, an inline error appears under a field, a cart badge ticks up, search results refresh as you type. A sighted user sees all of it. A screen-reader user, whose focus is elsewhere, gets nothing — the update is invisible to them. The work succeeded or failed and they have no idea.

This is exactly what WCAG 4.1.3 Status Messages requires: a status message must be presented to assistive tech without receiving focus. Live regions are the mechanism. Get them right and async UI becomes legible to everyone; get them wrong (or skip them) and a whole class of feedback simply does not exist for some of your users.

See it

Live demo
Tweak it3
Fire an update and read what a screen reader would announce — and how politeness changes timing.

Fire updates with Add to cart and Save, then switch the politeness knob and fire again. Each update changes the text of one persistent live region and is mirrored into the announcement log so sighted readers can see what a screen reader would speak. Set politeness to off and notice the log still updates while the region stays silent.

How it works

aria-live takes one of three values:

  • aria-live="polite" — the announcement waits for the screen reader to finish what it is currently saying, then reads the change. Use this for almost everything.
  • aria-live="assertive" — the announcement interrupts immediately, cutting off whatever is being spoken. Reserve it for genuine, time-sensitive errors.
  • aria-live="off" — the default; changes are not announced.

Two roles imply live regions, so you often do not need aria-live at all: role="status" is equivalent to aria-live="polite", and role="alert" is equivalent to aria-live="assertive". Two companions tune what gets read: aria-atomic="true" makes the screen reader announce the whole region as one unit (rather than only the changed node), and aria-relevant controls which kinds of change count (additions, removals, text — additions text is the default).

Build it

A persistent role="status" region whose text you set on an action, plus a separate role="alert" for a genuine error. Both elements are always rendered; only their text changes.

tsx
Two live regions: a polite status and an assertive alert
function SaveBar() {
  const [status, setStatus] = useState("");
  const [error, setError] = useState("");
 
  async function save() {
    setError("");
    setStatus("Saving…");
    try {
      await api.save();
      setStatus("Draft saved"); // updates the SAME region's text
    } catch {
      setStatus("");
      setError("Couldn't save — check your connection"); // interrupts
    }
  }
 
  return (
    <>
      <button type="button" onClick={save}>
        Save
      </button>
 
      {/* Polite: exists at all times, only its text changes. */}
      <p role="status">{status}</p>
 
      {/* Assertive: reserved for a real, time-sensitive error. */}
      <p role="alert">{error}</p>
    </>
  );
}

Make it yours

Use the controls beside the demo above to change aria-live politeness, aria-atomic, and show announcement log — each change updates the example live.

Experiment in the playground
  • Switch politeness to assertive and fire an update with a screen reader running — notice it cuts in immediately, which is why you save it for errors only.
  • Set politeness to off and watch the log keep filling while the region says nothing: proof that the visual change and the announcement are independent.
  • Fire several updates quickly and see how a polite region queues them — a hint at why announcing on every keystroke would overwhelm the user.

Reproduce it with an LLM

Reproduce it with an LLM

You are a senior front-end engineer. Add accessible announcements to a UI where things change without a page load — 'an item added to a cart, a form save that succeeds or fails, and a background sync status'. For each, choose the right live region: aria-live=polite (or role=status) for non-urgent updates that should wait for a pause, and aria-live=assertive (or role=alert) only for urgent, time-sensitive errors. Explain the rule for choosing between them, show the markup, and note the common mistakes: the live region must exist in the DOM before it updates, you should change its text content (not toggle it in/out), and you must not over-announce. Return the markup plus a short rationale.

Pitfalls & accessibility

  • A live region only conveys text, never color or icon — write announcements that fully stand on their own ("Couldn't save your changes", not just a red border), so the meaning survives with no visual at all.

Further reading