Skip to main content
Up Your A11y

Announcing Things That Change on the Page

Content that appears without a page load is invisible to a screen reader unless you announce it. Live regions, when to use them, and why most implementations announce nothing.

For developers who want to:

  • Understand why dynamically added content is silent by default
  • Choose between polite and assertive announcements
  • Avoid the live region mistakes that cause silence or noise
  • Know when a live region is the wrong tool and focus management is right

A client-rendered application changes content without a page load constantly: search results filter, a save succeeds, an item is removed from a basket, a validation message appears.

A sighted user sees it. A screen reader user, unless you do something, does not.

Why it is silent

A screen reader reads what it is focused on, and what the user navigates to. It does not continuously narrate the whole page.

When new content appears somewhere the user is not, nothing happens. There is no event they are told about. The content is in the accessibility tree, and they have no reason to go looking for it.

This is the same underlying problem as focus on route change, which is covered elsewhere on this site. The difference is that here the user has not navigated at all.

Live regions, briefly

A live region is an element whose changes the assistive technology should announce, marked with aria-live.

aria-live="polite" — announce when the user is idle. Correct for almost everything.

aria-live="assertive" — interrupt immediately. Reserved for things that genuinely cannot wait, such as a session about to expire or an error that blocks the current action.

There are also role shorthands: role="status" behaves as polite, role="alert" as assertive. These are usually the clearer choice because they carry a meaning as well as a behaviour.

The mistakes that make it not work

Almost every broken live region is one of these five.

The region is added at the same time as the content. If the element with aria-live appears in the DOM already containing its message, the change is frequently not announced. The container must exist and be empty first, and the content go into it afterwards.

It is conditionally rendered. {message && <div role="status">{message}</div>} looks reasonable and fails for the same reason. Render the container always; render the message inside it conditionally.

It is hidden with display: none. Hidden regions are not announced. To keep a message visually hidden but announced, use a visually-hidden class that keeps it in the accessibility tree, not display: none or visibility: hidden.

Everything is assertive. If every message interrupts, the user cannot get anything done. Assertive is for the rare case.

Too much changes at once. A live region wrapped around an entire results list announces the entire list. Announce a summary — "12 results" — not the content itself.

In React specifically

Render the container in the initial tree, outside whatever is being updated, so it is there before any message is.

Update its text content, do not replace the node. Changing the key or remounting the element defeats it.

Announce the same message twice deliberately. If a user triggers the same action and gets the same text, some screen readers will not announce an identical string again. A common approach is to append an invisible counter or to clear the region briefly before setting it.

One region, reused, is easier to reason about than several scattered ones.

When a live region is the wrong tool

This is the part most articles omit.

If something demands a response, move focus to it. A modal opening, an error that must be corrected before continuing, a step that has appeared — these need focus, not narration. Announcing something the user cannot then find is worse than silence.

If content is replaced wholesale, treat it as navigation. Filtering an entire page of results is closer to a route change than to a status update. Move focus to the results heading and let the user read from there.

If it is a form validation summary, focus it. That pattern is covered in the forms section of this site, and focus is the right answer there for the same reason: the user needs to act on it.

The rule of thumb: announce things the user should know about; move focus to things the user must do something about.

Checking it

Turn on a screen reader and perform the action.

If nothing is announced, work through the five mistakes above — it is almost always the conditional render.

If everything is announced twice, you probably have both a live region and a focus move competing.

If it is announced but you cannot then find the thing, you needed focus management rather than a live region.

[Suzanne: this sits naturally alongside your existing focus-on-route-change article and could link to it in both directions. A demo page would help here more than in most topics — a filter that announces correctly beside one that does not.]