WCAG 4.1.3: Status Messages
When something changes — a form is saved, a search returns results, an error appears, an upload finishes — sighted users simply see it. Under 4.1.3, screen reader users must be told too, without the page stealing their focus. The tool for the job is the ARIA live region: role="status", role="alert", and aria-live.
The success criterion, in full
In content implemented using markup languages, status messages can be programmatically determined through role or properties such that they can be presented to the user by assistive technologies without receiving focus.
Why status messages matter
Modern interfaces update constantly without reloading the page. You click "Save" and a green toast slides in. You type into a search box and a result count quietly updates. You submit a form and a red error banner appears at the top. For a sighted user these moments are obvious. For someone using a screen reader, the new text is silent — the cursor is somewhere else on the page, and nothing tells them anything happened.
That silence is the failure 4.1.3 exists to prevent. The naive fix — move focus to the new message — is often worse: it rips users out of the field they were filling, loses their place, and can trap them. The criterion instead requires a way to announce the change in place. ARIA live regions do exactly that: the screen reader speaks the new text while the user's focus never moves. Get this right and your app feels responsive to everyone; get it wrong and screen reader users are left guessing whether their action did anything at all.
What 4.1.3 actually requires
There are three testable ideas behind the criterion. Get these right and dynamic changes reach every user.
1. The message reports a status, not a routine UI change
4.1.3 covers messages about the outcome of an action, progress, or the state of the app — not every text change on the page.
A status message tells the user something happened: a form was submitted, a search returned 14 results, an item was added to the cart, an error occurred, or a file is still uploading. It is information the user needs but that does not, on its own, deserve to interrupt their work by stealing focus. Plain content updates that are not about status — a clock ticking, a value the user typed echoing back — are out of scope.
2. It must be announced without receiving focus
Sighted users see the new message appear; screen reader users must be told about it without the page yanking their focus to it.
The whole point of 4.1.3 is the no-focus-change constraint. You are not allowed to solve the problem by moving focus to the message (that would disrupt the user's place and is often worse). Instead the message must be exposed through an ARIA live region or an appropriate role so assistive technology speaks it while the user stays where they are. If announcing it requires moving focus, the design does not meet 4.1.3.
3. Use the right politeness and role for the urgency
Routine confirmations are polite (role="status"); errors that need immediate attention are assertive (role="alert").
role="status" (equivalent to aria-live="polite") queues the announcement so it does not interrupt whatever the screen reader is currently saying — right for success toasts, result counts, and saved confirmations. role="alert" (equivalent to aria-live="assertive") interrupts immediately — reserve it for errors and time-sensitive warnings. Over-using assertive live regions is itself a barrier because it constantly cuts the user off.
The rule of thumb:if a sighted user would notice a change because new text appeared — and you are notmoving focus to it — that text almost certainly belongs in a live region. Render the live-region container empty on load, then update its contents when the status changes.
What counts as a status message
The criterion is about messages that report state or the outcome of an action. These are the patterns that almost always need a live region:
Success & confirmation
"Changes saved", "Item added to cart", "Message sent" — use role="status" so it is announced politely.
Form & validation errors
"3 fields need your attention" appearing on submit without a focus move — use role="alert" for an immediate announcement.
Search & filter result counts
"14 results found" updating as the user types or filters. Polite role="status" avoids interrupting every keystroke.
Progress & loading states
"Uploading… 60%", "Loading results", "Upload complete". Announce milestones politely; avoid flooding with every percent.
What is NOT a 4.1.3 status message:changes that already move focus (a dialog that opens and is focused), content the user is directly editing and reading back, or a full navigation to a new page. And do not turn everything into a live region — an over-chatty interface that announces every minor change is as hostile as a silent one. Reserve live regions for genuine status.
Polite vs. assertive: choosing the right live region
- role="status" (aria-live="polite", aria-atomic="true" by default): the announcement waits for a pause. Use it for the vast majority of status messages — saves, result counts, non-urgent confirmations. It is the safe default.
- role="alert" (aria-live="assertive", aria-atomic="true" by default): interrupts the screen reader immediately. Reserve it for errors and warnings the user must hear at once. Over-using assertive regions makes an app exhausting to use.
- role="log" / role="progressbar" / role="marquee" / role="timer": specialised live regions for chat logs, progress, and scrolling/auto-updating text. Most teams only need status and alert.
- aria-live="polite" or "assertive" on a generic element: equivalent to the roles above when you cannot use a semantic role. Pair with aria-atomic="true" if you want the whole region re-read rather than just the changed node.
When in doubt, choose polite. An interruption you did not need is more disruptive than a confirmation that arrives a half-second late. See the ARIA reference for how these roles map to states and properties.
Scope and edge cases
4.1.3 is narrowly scoped to status messages presented without a focus change. Two clarifications keep you from misapplying it.
- Status messages are a WCAG 2.1 addition (Level AA). The criterion applies to messages that do not move focus; if your design legitimately moves focus to convey the change (for example focusing a newly-opened dialog and reading its content), 4.1.3 is not the criterion in play — but that focus move must still be appropriate and meet 2.4.3 Focus Order and related criteria.
- There is no exception for "the user can see it". Visibility to sighted users is exactly the gap 4.1.3 closes — if a change of status is presented visually, it must also be available to assistive technology without a focus change.
Code examples
A polite status region for confirmations
Render the container on initial load so it already exists when the text changes. A visually-hidden region works perfectly when the status is also shown elsewhere on screen.
<!-- Rendered EMPTY on page load -->
<div role="status" class="sr-only" id="save-status"></div>
<!-- Later, when the save succeeds, set the text -->
<script>
document.getElementById('save-status').textContent = 'Changes saved';
</script>An assertive alert for a form error summary
On submit, if you are not moving focus, an alert region announces the error immediately without disturbing the user's position.
<!-- Persistent container, empty until an error occurs -->
<div role="alert" id="form-errors"></div>
<script>
// Populate the EXISTING region — do not create it now.
document.getElementById('form-errors').textContent =
'3 fields need your attention. See the highlighted inputs below.';
</script>React: a reusable announcer
Mount the live region once near the app root, then push messages into it. Clearing and re-setting the text forces screen readers to re-announce an identical message.
function Announcer({ message, assertive = false }) {
return (
<div
role={assertive ? "alert" : "status"}
aria-live={assertive ? "assertive" : "polite"}
aria-atomic="true"
className="sr-only"
>
{message}
</div>
);
}
// The empty <Announcer /> is always in the tree; updating
// "message" state announces the change without moving focus.The visually-hidden utility
Use a class that hides the region visually but keeps it in the accessibility tree — never display:none, which removes it from live-region processing.
.sr-only {
position: absolute;
width: 1px; height: 1px;
padding: 0; margin: -1px;
overflow: hidden;
clip: rect(0 0 0 0);
white-space: nowrap;
border: 0;
}Common mistakes
- Injecting the live region and its text into the DOM at the same time — screen readers only announce changes to a region that already existed, so the message is silent.
- Hiding the region with display:none or visibility:hidden, which removes it from the accessibility tree; use a visually-hidden / sr-only class that keeps it present.
- Using role="alert" (assertive) for routine confirmations, constantly interrupting the user — reserve assertive for genuine errors and warnings.
- Auto-dismissing a toast before the announcement finishes, so the message disappears mid-sentence; keep it on screen long enough or store it for review.
- Re-setting the same text and expecting a re-announcement — identical content does not trigger an update; clear the region first, then set the new text.
- Flooding a polite region with rapid updates (every keystroke or every 1% of progress); debounce to meaningful milestones.
- Moving focus to the message as the 'fix', which disrupts the user's place — 4.1.3 specifically requires announcement without a focus change.
- Relying on title attributes or color-only changes to signal status, which assistive technology does not announce.
How to test for 4.1.3
- 1
Trigger each status with a screen reader running
Turn on NVDA, JAWS, or VoiceOver, then save a form, submit with errors, run a search, and start an upload. Confirm each change is spoken without your focus moving.
- 2
Verify focus never jumps
Keep focus in a known field, trigger the status, and check the cursor stays put. If focus moved, the design is solving the problem the wrong way for 4.1.3.
- 3
Inspect the live region in DevTools
Confirm the container exists on initial load (before the message), and that it carries role="status"/"alert" or an aria-live value. A region created together with its text is the classic failure.
- 4
Check politeness is appropriate
Errors and urgent warnings should interrupt (assertive); confirmations and counts should wait (polite). An interface that interrupts on every save is failing users even if it technically announces.
- 5
Test rapid and repeated messages
Fire the same status twice and a burst of quick updates. Make sure repeats re-announce when intended and that fast updates are debounced rather than lost or overwhelming.
Automated tools can confirm a live region exists but cannot judge whether the announcement actually fires or is appropriately urgent — that is a manual, screen-reader test. Build the workflow with the Screen Reader Testing guide, and scan a live page with the URL Accessibility Auditor.
Related success criteria
4.1.2 Name, Role, Value — A
The foundation 4.1.3 builds on: components must expose their name, role, and state to assistive technology. 4.1.3 extends that to status messages that appear dynamically.
3.3.1 Error Identification — A
Errors must be identified and described in text. When that error appears without a focus change, 4.1.3 governs how it is announced — the two work together on forms.
3.3.2 Labels or Instructions — A
Clear labels and instructions prevent errors in the first place; status messages catch the ones that still happen and report the outcome back to the user.
2.4.3 Focus Order — A
4.1.3 is partly about not moving focus. When you do move focus to convey a change instead, 2.4.3 ensures that move lands somewhere logical.
Browse every criterion in the WCAG Success Criteria hub or work through the full WCAG 2.2 checklist. For the building blocks behind live regions, see the ARIA reference and the Screen Reader Testing guide.
Frequently asked questions
What does WCAG 4.1.3 Status Messages require?
WCAG 4.1.3 (Level AA, added in WCAG 2.1) requires that status messages — text that reports the success or result of an action, the app's state, or progress — can be presented to assistive technology without receiving focus. In practice that means using an ARIA live region: role="status" or aria-live="polite" for routine confirmations and result counts, and role="alert" or aria-live="assertive" for errors and urgent warnings. The screen reader announces the change while the user stays exactly where they are.
What is the difference between role="status" and role="alert"?
role="status" maps to aria-live="polite": the announcement waits until the screen reader finishes what it is currently saying, so it never interrupts the user. Use it for success messages, "saved", search result counts, and loading-complete notices. role="alert" maps to aria-live="assertive": it interrupts immediately. Reserve it for errors and time-sensitive information the user must hear right away. Both roles create an implicit live region, so you do not also need to add aria-live — using the role is usually the simplest and most reliable choice.
Why doesn't my aria-live region get announced?
The most common reason is that the live region was added to the DOM at the same moment as its text. Screen readers only announce changes to a live region that already existed when the change happened. The reliable pattern is to render the empty container (the element with role="status" or aria-live) on initial page load, then inject the text into it later. Other frequent causes: the region is display:none (move it offscreen with a visually-hidden class instead), the text is set before the browser has registered the region, or two updates fire so fast the first is lost — debounce them into one update.
How do I announce form validation errors for 4.1.3?
There are two complementary techniques. On submit, if you do not move focus to the first invalid field, put the error summary in a live region — role="alert" for an immediate, assertive announcement — so the screen reader reads it without a focus change. For inline per-field errors, associate the error text with the input using aria-describedby and set aria-invalid="true"; that satisfies 3.3.1 Error Identification when the field receives focus. Many robust forms do both: move focus to an error summary on submit and wire up aria-describedby on each field.
Does showing a toast notification automatically meet 4.1.3?
No. A toast is only accessible if its container is a live region that existed before the toast text appeared. The common failure is mounting the toast element and its text together, which screen readers miss. Render a persistent live-region container (role="status" for routine toasts, role="alert" for errors) once, then push each toast's text into it. Also keep toasts on screen long enough to be read, or provide a place users can review them, because an auto-dismissing toast that vanishes in two seconds can be gone before the announcement finishes.
Is 4.1.3 the same as 3.3.1 Error Identification?
They overlap but are distinct. 3.3.1 Error Identification (Level A) requires that input errors are identified and described in text. 4.1.3 Status Messages (Level AA) governs how a status — including an error message that appears dynamically — is conveyed to assistive technology without moving focus. A form error often needs both: the error text must exist and describe the problem (3.3.1), and if it appears without a focus change it must be in a live region so screen readers announce it (4.1.3).