patternjavascriptMajor
aria-live regions — announcing dynamic content to screen readers
Viewed 0 times
ARIA 1.1+
aria-livelive regiondynamic contentannouncementstoast notificationsstatus messages
Problem
When page content updates dynamically (toast notifications, form validation errors, status messages, live search results), screen reader users receive no notification unless the change is in their current reading position.
Solution
Use aria-live regions to announce dynamic updates. Inject a visually hidden announcer element on page load and update its text content programmatically.
// Minimal live region setup
<div
role="status"
aria-live="polite"
aria-atomic="true"
className="sr-only"
/>
// aria-live values
// 'polite' — announces after current speech finishes (most updates)
// 'assertive' — interrupts immediately (errors, urgent alerts only)
// 'off' — no announcements
// React announcer hook
function useAnnounce() {
const ref = useRef(null);
const announce = useCallback((message) => {
if (ref.current) {
ref.current.textContent = '';
// Force re-read by clearing then setting
requestAnimationFrame(() => {
ref.current.textContent = message;
});
}
}, []);
return { ref, announce };
}
// Minimal live region setup
<div
role="status"
aria-live="polite"
aria-atomic="true"
className="sr-only"
/>
// aria-live values
// 'polite' — announces after current speech finishes (most updates)
// 'assertive' — interrupts immediately (errors, urgent alerts only)
// 'off' — no announcements
// React announcer hook
function useAnnounce() {
const ref = useRef(null);
const announce = useCallback((message) => {
if (ref.current) {
ref.current.textContent = '';
// Force re-read by clearing then setting
requestAnimationFrame(() => {
ref.current.textContent = message;
});
}
}, []);
return { ref, announce };
}
Why
Screen readers only announce content that changes inside a watched region, or that receives focus. Without aria-live, dynamic updates are silently invisible to AT users.
Gotchas
- The aria-live region must exist in the DOM before content is injected — adding it dynamically is unreliable
- Clearing and resetting text content (via requestAnimationFrame) ensures the same message is re-announced if repeated
- Use aria-live='assertive' sparingly — it interrupts the user mid-sentence and is annoying if overused
- aria-atomic='true' means the entire region is announced, not just the changed portion — use for complete messages
- role='alert' is equivalent to aria-live='assertive' aria-atomic='true' — use for error messages
Context
Any UI with status updates, loading states, validation feedback, or real-time data
Revisions (0)
No revisions yet.