4.1.3 Status Messages
Level: AA | Principle: Robust | Since: WCAG 2.1 | Automation: Partial (axe-core)
What This Means
Status messages that provide information to the user about the success or result of an action, the progress of a process, or the existence of errors must be programmatically communicated to assistive technologies using ARIA live regions — without moving focus to the message. Sighted users can see a toast notification or inline confirmation; screen reader users need those same messages announced automatically.
Who This Affects
- Screen reader users — without ARIA live regions, status messages appear silently on screen and are never announced; users have no idea something happened
- Voice control users — they need to know when an action succeeded or failed so they can decide what to do next
- Cognitive disability users — audible confirmation from a screen reader reinforces that their action worked
Common Pitfalls
1. Success message with no ARIA live region
<!-- Bad: screen readers never announce this -->
<div class="toast success">Item added to cart!</div>
<!-- Good: role="status" creates a polite live region -->
<div class="toast success" role="status">Item added to cart!</div>
2. Error count update without announcement
<!-- Bad: the count changes visually but is not announced -->
<span class="error-count">3 errors found</span>
<!-- Good: aria-live="polite" announces changes -->
<span class="error-count" aria-live="polite">3 errors found</span>
3. Search results count not announced
<!-- Bad: user has no idea results loaded -->
<p class="results-count">42 results found</p>
<!-- Good: screen reader announces the result count -->
<p class="results-count" role="status">42 results found</p>
4. Loading spinner with no announcement
<!-- Bad: visual spinner but no announcement -->
<div class="spinner"></div>
<!-- Good: aria-live region announces loading state -->
<div aria-live="polite" class="loading-status">
Loading results...
</div>
5. Using aria-live="assertive" for non-urgent messages
<!-- Bad: assertive interrupts the user immediately -->
<div aria-live="assertive">Your preferences have been saved.</div>
<!-- Good: polite waits for the user to finish what they're doing -->
<div aria-live="polite">Your preferences have been saved.</div>
How to Fix
Use role="status" for success/info messages
<!-- role="status" is equivalent to aria-live="polite" + aria-atomic="true" -->
<div role="status">
Your changes have been saved.
</div>
Use role="alert" for error messages that need immediate attention
<!-- role="alert" is equivalent to aria-live="assertive" -->
<div role="alert">
Payment failed. Please check your card details and try again.
</div>
Use aria-live="polite" for progressive updates
<div aria-live="polite">
<p>Uploading: 45% complete</p>
</div>
Toast notification component with proper ARIA
function Toast({ message, type }) {
const role = type === 'error' ? 'alert' : 'status';
return (
<div className={`toast toast-${type}`} role={role}>
{message}
</div>
);
}
Important: the live region must exist in the DOM before content changes
<!-- The container must be present in the DOM FIRST -->
<div id="status" role="status"></div>
<script>
// Then inject content — the screen reader will announce it
document.getElementById('status').textContent = '5 items added to cart.';
</script>
<!-- Bad: inserting the entire element dynamically often fails to trigger announcement -->
How to Test
- Perform actions that trigger status messages: add items to a cart, submit a form, run a search, trigger an error.
- Open a screen reader and repeat those actions. Verify each status message (success toast, error alert, search result count, loading indicator) is announced without focus moving to the message.
- Inspect the status message elements in DevTools and confirm they use
role="status"(for non-urgent messages) orrole="alert"(for errors), or appropriatearia-livevalues. - Verify that the live region container exists in the DOM before the message content is injected (inserting the whole element dynamically may fail to trigger announcement).
- Pass: All status messages are announced by screen readers via proper ARIA live regions without stealing focus.
- Fail: Any status message appears visually but is not announced by screen readers, or an
aria-live="assertive"region is used for non-urgent messages.
axe-core Rules
| Rule | What It Checks |
|------|---------------|
| aria-live-region-attr | Ensures ARIA live region attributes are valid |
Tools
Test this criterion with the ARIA Validator.