role=“status”, role=“alert” and role=“log” Compared

Permalink to "role=“status”, role=“alert” and role=“log” Compared"

status, alert and log are ARIA roles that create live regions with built-in defaults, so authors do not have to remember the right combination of aria-live, aria-atomic and aria-relevant. Each fits one kind of message. The common failure is using alert for everything — “Saved”, “12 results”, “Sorted” — so every status interrupts whatever the user was listening to, and the genuinely urgent message is indistinguishable from the rest.

This page compares the three roles, their defaults and their intended uses in data interfaces. It belongs to ARIA live regions for dynamic data and complements choosing between polite and assertive aria-live regions.

Spec reference

Permalink to "Spec reference"
Role Implicit aria-live Implicit aria-atomic Implicit aria-relevant Purpose (ARIA 1.2)
status polite true additions text Advisory information that is not important enough to justify an alert
alert assertive true additions text Important, usually time-sensitive information
log polite false additions New information added in meaningful order, where old information may disappear

A related role, marquee, is off by default and exists for non-essential scrolling content; timer is also off. Neither is useful for data interfaces in practice.

SC 4.1.3 Status Messages is satisfied by any of the three, provided the message is present in the region’s content. The understanding document’s examples map neatly: a search result count is a status, an error preventing submission can be an alert, and a chat transcript is a log.

status versus alert, by what happens to speech Comparison of role status and role alert by how each treats the user's current speech and what each is appropriate for. status versus alert, by what happens to speech✓ role="status" (polite)Waits until current speech finishesSort, filter and page resultsSaved, copied, exportedBackground sync finished✓ role="alert" (assertive)Interrupts current speechSession about to expireSave failed; data not storedConnection lost during live editing
The difference is interruption — use it only when waiting would cost the user something.

When to use each role — and when not to

Permalink to "When to use each role — and when not to"

status is the default for a data interface. Almost every message a table or dashboard produces is the result of something the user just did, and the user is waiting for it: they will hear it as soon as the current utterance ends.

alert is for problems with a cost to waiting. A failed save that the user does not hear about is data loss. A session timeout warning they hear thirty seconds late may be too late. Keep the list of alert-worthy events short and explicit.

log is for sequences: an import progress feed, an activity stream, a chat panel, streaming log lines. Only the newly appended entry is read; earlier entries stay available for reading but are not repeated. The full treatment is in accessible live log viewers.

Do not use alert for validation errors that appear as the user types. Each keystroke that toggles an error interrupts their typing feedback. Attach field errors with aria-describedby and announce a summary only on submit.

Annotated code example

Permalink to "Annotated code example"
<!-- One of each, rendered with the page and never removed -->

<!-- SC 4.1.3: routine results; polite + atomic by role -->
<div role="status" class="visually-hidden" id="sr-status"></div>

<!-- SC 4.1.3: urgent problems only; assertive + atomic by role -->
<div role="alert" class="visually-hidden" id="sr-alert"></div>

<!-- A visible activity feed: polite, additions only, not atomic -->
<ol role="log" aria-label="Import progress" id="import-log"></ol>
// A tiny router so call sites choose intent, not ARIA
const regions = {
  status: document.getElementById('sr-status'),
  alert: document.getElementById('sr-alert'),
};
export function notify(message, { urgent = false } = {}) {
  const el = urgent ? regions.alert : regions.status;
  el.textContent = '';
  requestAnimationFrame(() => { el.textContent = message; });
}

// Call sites
notify('Sorted by Amount, descending.');                       // status
notify('Could not save row INV-1042. Changes kept locally.', { urgent: true });  // alert

// Log entries are appended, never replaced
function logLine(text) {
  const li = document.createElement('li');
  li.textContent = text;
  document.getElementById('import-log').append(li);             // only this is read
}

Routing by intent — urgent: true — keeps ARIA decisions in one place. Engineers deciding whether a message is urgent is a product question; engineers remembering which role is assertive is an avoidable bug.

Keyboard & AT behaviour

Permalink to "Keyboard & AT behaviour"
Region NVDA JAWS VoiceOver TalkBack
status Queued after current speech Queued Queued; may drop if another arrives quickly Queued
alert Interrupts Interrupts Interrupts Queued on some versions
log append New entry only New entry only New entry only New entry only
alert inserted with text Usually spoken (special-cased) Usually spoken Usually spoken Varies

The last row is a quirk worth knowing: browsers special-case role="alert" so that an alert element inserted into the page with its text already present is announced. That makes alert more forgiving than status, and is part of why it gets overused. Do not let the quirk drive the role choice.

Interruptions in an example ten-minute session Bar chart for an example ten-minute session with 34 status messages, two of them failures, comparing interruptions when every message uses role alert versus when only failures do. Interruptions in an example ten-minute sessionEvery message as alert34 interruptions — sort, filter, save, page…Alert for failures only2 interruptions
In this example session, reserving alert for failures cuts interruptions from 34 to the 2 that matter.

Integration context

Permalink to "Integration context"

In React and other component frameworks, render the regions once at the root and expose a notify function; live regions in React without lost announcements shows the pattern. For many competing messages from one action, queueing and merging are covered in announcement queues for competing messages.

The implicit defaults are why aria-atomic and aria-relevant rarely need setting explicitly: status and alert are already atomic, and log already reads only additions.

Which role for this message? Decision tree for choosing role status, alert or log based on whether the message is urgent and whether messages accumulate as a sequence. Which role for this message?What kind of message is it?Result or updaterole="status"polite; waits its turnUrgent problemrole="alert"assertive; interruptsOne of a sequencerole="log"reads only the new entry
Start from the message, not from the component that produces it.

Gotchas

Permalink to "Gotchas"

aria-live="assertive" on role="status". Explicit attributes override the role’s defaults, producing an assertive status. Occasionally deliberate, usually a copy-paste accident.

Alerts that repeat. A persistent error banner with role="alert" that is re-rendered on every state change re-announces on every render. Render it once and change it only when the error changes.

Visible alerts that steal focus. An alert should not also move focus; the whole point is that the message is heard without focus moving. If the user must act, use a dialog.

Testing checklist

Permalink to "Testing checklist"

FAQ

Permalink to "FAQ"
What is the difference between role="status" and role="alert"?

Both are live regions that read their whole content, but status is polite — it waits for current speech to finish — while alert is assertive and interrupts. Use status for routine results and alert only for urgent problems.

Do I need aria-live on an element with role="status"?

No. role=“status” already implies aria-live=“polite” and aria-atomic=“true”. Adding aria-live only matters if you intend to override those defaults, which is rarely the right call.

When should I use role="log"?

For content that grows as a sequence — activity feeds, import progress, chat, streaming logs — where only the newest entry should be read and earlier entries remain available in the page.

Why is role="alert" announced even when it is added with text already inside?

Browsers special-case alerts so that inserting an alert element fires an alert event. That makes alerts forgiving, but it is not a reason to use alert for non-urgent messages.

Permalink to "Related"

← Back to ARIA Live Regions for Dynamic Data