4.1.3 Status Messages
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.
What this rule means
WCAG 4.1.3 Status Messages requires that important messages conveyed to users — such as success confirmations, error summaries, progress updates, and search result counts — are communicated to assistive technology without moving keyboard focus to the message. This is achieved through ARIA live regions: elements with role="status", role="alert", role="log", role="progressbar", or the aria-live attribute.
A status message is any content update that provides information to the user about the success or result of an action, the waiting state of an application, or the progress of a process, and is not important enough to justify a focus change. If a user submits a form and a "Your changes have been saved" banner appears, a sighted user sees it immediately. A screen reader user needs the same message announced without losing their current position on the page.
Why it matters
Sighted users notice visual changes — a toast notification, a loading spinner, an error banner — because their eyes can scan the page. Screen reader users, however, only hear what the screen reader announces. If a status message appears visually but is not exposed through a live region, the screen reader remains silent. The user has no idea their form was saved, their search returned zero results, or an error occurred.
This is particularly problematic for asynchronous operations common in modern web applications. AJAX form submissions, real-time validation, search-as-you-type, file upload progress, and shopping cart updates all generate status messages that must be announced without disrupting the user's focus.
Related axe-core rules
There are currently no axe-core rules that directly test for 4.1.3 compliance. Status messages require manual testing to verify that appropriate ARIA live regions are in place and that screen readers announce updates correctly. Automated tools can verify the presence of live region attributes, but they cannot determine whether every status message in the application is covered.
How to test
Testing status messages is primarily a manual process. You need to perform actions that generate status updates and verify they are announced by a screen reader.
- Identify all status messages in the application: form success/error messages, search result counts, loading indicators, cart updates, toast notifications, and progress indicators.
- Enable a screen reader (VoiceOver on macOS, NVDA on Windows) and trigger each status message.
- Confirm the screen reader announces the message without focus moving away from your current position.
- Verify that urgent messages (errors, warnings) use role="alert" or aria-live="assertive" and are announced immediately.
- Verify that non-urgent messages (success, info, progress) use role="status" or aria-live="polite" and are announced after the screen reader finishes its current speech.
- Check that the live region container exists in the DOM before the message is injected — dynamically created live regions may not be recognized by all screen readers.
How to fix
Use ARIA live regions to announce status messages. The key is choosing the right level of urgency and ensuring the live region is present in the DOM before content is injected.
Success message with role="status"
<!-- The live region container is in the DOM on page load (empty) -->
<div role="status" aria-live="polite" id="form-status"></div>
<!-- After form submission, inject the message -->
<script>
document.getElementById('form-status').textContent =
'Your changes have been saved successfully.';
</script>
Error alert with role="alert"
<!-- Container present in DOM from the start -->
<div role="alert" aria-live="assertive" id="error-alert"></div>
<!-- When an error occurs -->
<script>
document.getElementById('error-alert').textContent =
'Error: Unable to save. Please check your internet connection.';
</script>
Search results count
<!-- Live region for search feedback -->
<div role="status" aria-live="polite" aria-atomic="true" id="search-results-count">
Showing 24 results for "accessibility"
</div>
<!-- Updated when the user types -->
<script>
function updateResults(query, count) {
document.getElementById('search-results-count').textContent =
`Showing ${count} results for "${query}"`;
}
</script>
Progress indicator
<!-- Progress bar with live region -->
<div
role="progressbar"
aria-valuenow="45"
aria-valuemin="0"
aria-valuemax="100"
aria-label="File upload progress"
aria-live="polite"
>
45% complete
</div>
<!-- Completion message -->
<div role="status" aria-live="polite" id="upload-status"></div>
<script>
// When upload finishes:
document.getElementById('upload-status').textContent =
'Upload complete. File "report.pdf" has been saved.';
</script>
React implementation pattern
function StatusAnnouncer({ message, urgency = "polite" }) {
return (
<div
role={urgency === "assertive" ? "alert" : "status"}
aria-live={urgency}
aria-atomic="true"
className="sr-only"
>
{message}
</div>
);
}
// Usage in a form component
function ContactForm() {
const [status, setStatus] = useState("");
async function handleSubmit(data) {
try {
await submitForm(data);
setStatus("Message sent successfully.");
} catch {
setStatus("Failed to send message. Please try again.");
}
}
return (
<form onSubmit={handleSubmit}>
{/* form fields */}
<button type="submit">Send</button>
<StatusAnnouncer message={status} />
</form>
);
}
Common mistakes
- Creating the live region dynamically at the same time as the message — many screen readers only track live regions that were present in the DOM before content changed.
- Using role="alert" for non-urgent messages like "Saved successfully" — assertive announcements interrupt the user and should be reserved for errors and warnings.
- Moving focus to the status message instead of using a live region — this disrupts the user's position and violates the intent of 4.1.3.
- Forgetting aria-atomic="true" when the entire message should be re-read on update, not just the changed portion.
- Using aria-live on a container that has frequent rapid updates (e.g., a real-time log) without debouncing — this floods the screen reader with announcements.
- Placing the live region inside a container that is hidden with display:none or visibility:hidden — live regions must be visible to the accessibility tree to function.
Resources
- W3C WAI: ARIA Live Regions— W3C WAI
- Deque: aria-live regions best practices— Deque University
- WebAIM: ARIA Live Regions— WebAIM
- The A11Y Project: Notifications— A11Y Project