aria-atomic and aria-relevant in Practice
Permalink to "aria-atomic and aria-relevant in Practice"aria-atomic decides whether a screen reader speaks only the part of a live region that changed or the whole region. aria-relevant decides which kinds of change — added nodes, removed nodes, text changes — count as announceable at all. Both are widely set by copy-paste and widely misunderstood; this page covers what they really do, how inconsistently they are supported, and the small set of cases in data interfaces where setting them makes a difference.
It belongs to ARIA live regions for dynamic data.
Spec reference
Permalink to "Spec reference"aria-atomic (true | false, default false; true implicitly on role="status" and role="alert"). When true, assistive technology should present the entire region as a whole when any part changes. When false, it presents only the changed nodes.
aria-relevant (space-separated tokens: additions, removals, text, all; default additions text; role="log" defaults to additions). It tells assistive technology which mutations to report.
Support in practice: aria-atomic="true" is honoured by NVDA, JAWS and VoiceOver, with occasional quirks. aria-relevant is honoured patchily — removals in particular is ignored by several screen reader and browser combinations. The ARIA specification itself notes that authors should not rely on removals.
Criterion: SC 4.1.3 Status Messages. Neither attribute is required for conformance; both shape whether a status message is understandable when it is spoken.
When to set them — and when not to
Permalink to "When to set them — and when not to"Set aria-atomic="true" when a region is a sentence with a changing part: “Showing 14 of 480 results”, “Balance: 1,240.00”, “Last updated 10:05”. Without it, only the changed span may be spoken, stripped of meaning. role="status" already implies it, which is one reason to prefer role="status" for such messages.
Do not set it on a log or feed that grows by appending — every new line would re-read the whole history. role="log" defaults to aria-atomic="false" for this reason.
Leave aria-relevant alone in nearly every case. The default, additions text, covers new messages and changed text. If you find yourself reaching for removals — to announce that a row was deleted, say — write an explicit message instead: “Invoice INV-1042 deleted.” Removals support is too inconsistent to depend on, and a removal announced by itself (“INV-1042”) is ambiguous anyway.
The misapplication to name is aria-relevant="all" on a region that is updated by replacing its content. Every update is then a removal plus an addition, and readers that honour both speak the old content and the new.
Annotated code example
Permalink to "Annotated code example"<!-- Sentence with a changing number: atomic, so the sentence is read whole -->
<p role="status" id="result-count"> <!-- role=status implies aria-atomic=true -->
Showing <span id="shown">12</span> of 480 invoices
</p>
<!-- The same with a plain live region: atomic must be explicit -->
<p aria-live="polite" aria-atomic="true" id="sync"> <!-- SC 4.1.3 -->
Last sync <time id="sync-time">10:02</time>
</p>
<!-- Append-only activity log: atomic false, additions only (the role's defaults) -->
<ol role="log" aria-label="Import activity" id="import-log">
<li>Row 1 imported</li>
</ol>
// Updating only the number is fine when the region is atomic
document.getElementById('shown').textContent = '14'; // reads "Showing 14 of 480 invoices"
// Deleting a row: do not rely on aria-relevant="removals"
function onDelete(row) {
row.remove();
status(`Invoice ${row.dataset.id} deleted.`); // explicit, complete message
}
A simpler alternative to atomic regions is to replace the whole text of the region every time. If the entire message is one text node, atomic and non-atomic regions behave the same, because the changed part is the whole message. Many teams standardise on that and never set aria-atomic at all.
Keyboard & AT behaviour
Permalink to "Keyboard & AT behaviour"| Setup | NVDA + Chrome | JAWS + Chrome | VoiceOver + Safari |
|---|---|---|---|
| Atomic sentence, number changes | Whole sentence | Whole sentence | Whole sentence |
| Non-atomic sentence, number changes | “14” | “14” | Sometimes the whole sentence |
aria-relevant="removals", node removed |
Removed text read | Often ignored | Often ignored |
role="log", row appended |
New row only | New row only | New row only |
aria-relevant="all", content replaced |
Old then new | New only | New only |
Integration context
Permalink to "Integration context"These attributes are the fine-tuning layer on top of politeness. Decide polite or assertive first, as in choosing between polite and assertive aria-live regions, then pick the role, as in role status, alert and log compared — the role sets sensible defaults for both attributes.
KPI cards that update a value inside a labelled card are the classic atomic case in dashboards; see accessible KPI cards and sparklines.
Gotchas
Permalink to "Gotchas"Nested live regions. A live region inside another live region produces double announcements in some readers, and the outer region’s aria-atomic can pull in the inner region’s text. Do not nest them.
Atomic regions with interactive content. A region containing a button re-reads the button’s name on every update. Keep live regions to text.
Frameworks that patch text nodes. React and Vue may update only a text node inside a span, which is exactly the “partial change” case. If a message sometimes reads as a bare number, the framework is doing a minimal update inside a non-atomic region.
Design system notes
Permalink to "Design system notes"A shared status component can hide these attributes from product teams entirely. Offer two components — a StatusMessage that always renders role="status" and replaces its whole text, and an ActivityLog that renders role="log" and only appends — and do not accept aria-atomic or aria-relevant as props on either. The role defaults are correct for their intended use, and every custom combination teams have reached for in practice has been a bug.
Testing checklist
Permalink to "Testing checklist"FAQ
Permalink to "FAQ"What does aria-atomic="true" do?
It tells assistive technology to read the entire live region whenever any part of it changes, instead of only the changed part. It is implied by role=“status” and role=“alert”.
Should I use aria-relevant="removals" to announce deleted rows?
No. Support is inconsistent and several screen readers ignore it. Write an explicit status message such as “Invoice INV-1042 deleted” when something is removed.
Do I need aria-atomic if I replace the whole message each time?
No. When the region’s content is a single text node that you replace entirely, the changed part is the whole message, so atomic and non-atomic regions behave the same.
Why does my result count region only say the number?
Because the region is not atomic and your framework updated only the text node holding the number. Make the region atomic, or use role=“status”, which implies it.
Related
Permalink to "Related"- role status, alert and log — roles that set these defaults
- Polite versus assertive — the other live region setting
- Accessible KPI cards — a region where atomic matters