In an ARIA live region such as <p aria-live="polite">Showing <span>12</span> results</p>, what does aria-atomic control, and what does the default aria-atomic="false" mean when only the number changes?
answer
- how much gets read, not what changed
- false is the default
- bare number with no noun
- nearest ancestor that sets it
- status and alert are atomic already
basics
~20 saria-atomic decides how much of a live region is announced when part of it changes. The default, false, announces only the changed part — so the region above says just "13". Setting aria-atomic="true" re-reads the whole region: "Showing 13 results".
solid answer
~40 s`aria-atomic` answers "how much context comes with the change". With the default `aria-atomic="false"`, the screen reader announces only the changed node, so a counter whose surrounding words never change is announced as a bare "13" — technically correct and useless out of context. With `aria-atomic="true"`, the assistive technology re-reads the entire live region as one unit, so the user hears "Showing 13 results". The value is resolved by walking up from the changed node to the nearest ancestor that sets it, which is why putting `aria-atomic="true"` on the region works even though the change happened in a descendant `<span>`. `role="status"` and `role="alert"` already imply atomic true, which is another reason to prefer them for single-sentence messages; `role="log"` deliberately does not, because a chat transcript should announce only the new line.
code
html · 9 lines<!-- Default: only the changed text node is announced -> "13" -->
<p aria-live="polite">Showing <span id="a">12</span> results</p>
<!-- Atomic: the whole region is re-read -> "Showing 13 results" -->
<p aria-live="polite" aria-atomic="true">Showing <span id="b">12</span> results</p>
<button type="button" onclick="a.textContent = '13'; b.textContent = '13';">
Update count
</button>go deeper
Know that aria-atomic decides whether the screen reader reads the whole live region or only the bit that changed, and that the default reads only the changed bit.
Explain the ancestor lookup that resolves the value, why a lone counter announces as a bare number, and which live roles already imply aria-atomic="true".
Show the production instinct: write complete self-contained sentences into a small atomic region rather than tuning granularity on a large one, and use aria-busy only for genuinely staged updates with a guaranteed reset.
Own the pattern across teams — a shared status component that emits full sentences into one atomic region, so individual features never have to reason about announcement granularity at all.
## The property in one line `aria-atomic` controls the *granularity* of a live-region announcement: is the changed fragment presented on its own, or is the whole region presented as one indivisible unit? ## The default and why it surprises people The default is `aria-atomic="false"`. Given: ```html <p aria-live="polite">Showing <span id="n">12</span> results</p> ``` changing the span's text from `12` to `13` announces "13". The words "Showing" and "results" never changed, so they are not part of the change, so they are not spoken. A sighted user reads the full sentence; a screen-reader user hears a number with no noun attached to it. If several such counters exist on the page, the user cannot tell which one just spoke. Setting the property fixes it: ```html <p aria-live="polite" aria-atomic="true">Showing <span id="n">12</span> results</p> ``` Now the change to the span causes the whole paragraph to be announced: "Showing 13 results". ## How the value is resolved The change happens on a descendant node, but you set `aria-atomic` on the region. That works because assistive technology walks up the ancestor chain from the changed node looking for the nearest element that specifies `aria-atomic`, and the value it finds decides what gets read — and that ancestor's whole subtree is what is presented. This is why you set the property once on the region rather than on every element that might change inside it. It also means you can be selective in a larger region: an inner element marked `aria-atomic="true"` will be read whole even if the outer region is non-atomic. ## The roles already choose for you `role="status"` and `role="alert"` imply `aria-atomic="true"`. That is the right default for a single-sentence message, and it is a good reason to write `<p role="status">` rather than assembling `aria-live` and `aria-atomic` by hand. `role="log"` implies `aria-atomic="false"`, deliberately: in a chat window or an activity feed, each new entry is the news, and re-reading the entire transcript on every message would be intolerable. ## Its companion: aria-relevant Where `aria-atomic` says *how much*, `aria-relevant` says *which kinds of change count*. Its values are `additions`, `removals`, `text` and `all` (the first three are space-separable), and the default is `additions text` — nodes being added and text being changed are announced, node removals are not. ```html <ul aria-live="polite" aria-relevant="additions removals"> ``` That would also announce items disappearing. In practice `aria-relevant` is the least useful of the live-region properties: support is uneven, `removals` announcements are usually noise ("the thing you were told about is gone" rarely helps), and it is easy to reach for it when the real answer is to write a clear sentence into a `role="status"` region instead. Know it exists, know the default, and be able to say you would rarely change it. ## aria-busy for multi-step updates If a region is rebuilt in several steps — clear it, then insert rows, then update a count — each step is a change and each may be announced, producing a stutter. `aria-busy="true"` on the region tells assistive technology that it is mid-update and to hold announcements; setting it back to `false` when the update settles causes the finished state to be presented once. Treat it as the escape hatch for genuinely staged updates, and set it back to `false` reliably (including on the error path), because a region left busy forever is a region that never announces again. ## Putting it together A search-results status that behaves well typically looks like this: ```html <p id="results-status" role="status" class="visually-hidden"></p> ``` and receives a complete, self-contained sentence — `"13 results for \"laptop\""` — rather than a bare number wired into surrounding static text. Writing whole sentences into an atomic region sidesteps most of the granularity questions entirely: there is no partial change to mis-announce, because the region only ever contains one message at a time. ## Mistakes to avoid - Assuming the whole region is read by default. It is not; `false` is the default and partial announcements are the common complaint. - Setting `aria-atomic="true"` on a long region — a whole results table, a chat history — so every small change re-reads a wall of text. - Confusing `aria-atomic` with `aria-relevant`: one is how much of the region, the other is which kinds of mutation qualify. - Setting `aria-busy="true"` and forgetting to clear it, which silences the region permanently.
- What does aria-relevant do, and what is its default?`aria-relevant` says which kinds of mutation count as an announceable change: `additions`, `removals`, `text`, or `all`. The default is `additions text`, so added nodes and changed text announce while removals do not. Support is uneven and removal announcements are usually noise, so it is rarely worth overriding.
- A region is rebuilt in several steps and stutters as it announces each one. What helps?Set `aria-busy="true"` on the region before the multi-step update and back to `false` when it settles; assistive technology holds announcements while busy and presents the finished state once. Clear it on every path, including errors — a region left busy stops announcing entirely.
- Why does role="log" not imply aria-atomic="true" when status and alert do?Because a log is an append-only stream — a chat transcript, an activity feed — where the newly added entry is the news. Re-reading the entire history on every message would bury the update, so log deliberately keeps the non-atomic default while status and alert, which hold one short message, are atomic.
saying these in an interview costs you the question
- Thinks the whole region is announced by default
- Confuses aria-atomic with aria-relevant
- Puts aria-atomic="true" on a large table or transcript
- Adds aria-atomic to role="status" believing it is required
- Leaves aria-busy="true" set after the update finishes