· 6 min read
ariaNotify(): screen reader announcements without live regions
ariaNotify() lets you make screen readers speak from JavaScript with one call, no hidden live region needed. Here is how it works and when to use it.

ariaNotify() is a browser method that tells the screen reader to say a piece of text, with no hidden live region and no DOM change required. You call document.ariaNotify("Saved") or the same method on an element, and the text goes into the screen reader's speech queue. It became Baseline in September 2026 when Safari 27 shipped it, joining Chrome and Edge 141 and Firefox 150.
For years the only way to make a screen reader speak from script was to change the text inside an ARIA live region and hope the timing worked out. This API replaces that indirection with a direct call.
What is ariaNotify()?
A screen reader is software that reads the page aloud for people who can't see it, using the browser's accessibility tree rather than the pixels. An ARIA live region is an element marked with aria-live (or a role like status or alert) whose content changes get announced automatically.
ariaNotify() skips the live region. It takes a string and an optional options object, queues that string for announcement, and returns undefined.
document.ariaNotify('Draft saved');
// interrupt whatever is being read right now
document.ariaNotify('Connection lost. Retrying.', { priority: 'high' });
It exists on both Document and Element. The behavior is the same; the difference is which lang attribute picks the voice. Called on an element, the browser looks at that element's lang or its nearest ancestor's. Called on the document, it uses the lang on <html>. If neither is set, the user agent's default language wins.
How is ariaNotify() different from a live region?
Live regions work, but they have rules that are easy to get wrong. The region usually needs to be in the DOM before its content changes, or nothing is announced. Setting the same text twice in a row may be ignored. What gets read is whatever ends up in the node, so you often keep a visually hidden <div> around just to hold sentences that don't belong in the visible UI.
ariaNotify() removes those constraints:
| Live region | ariaNotify() | |
|---|---|---|
| Needs a DOM node | Yes, present before the update | No |
| Text comes from | The node's content | The string you pass |
| Triggered by | A DOM mutation | A method call |
| Urgency | aria-live="polite" or "assertive" | priority: "normal" or "high" |
| Works in older browsers | Yes | Only recent versions |
The two priorities map roughly onto the live region values. "normal", the default, waits until the screen reader finishes its current speech, like polite. "high" interrupts, like assertive. One detail to remember: if a live region and ariaNotify() both fire, the live region's announcement takes precedence.
When should you use ariaNotify()?
Use it for events that change state without moving focus or adding meaningful content to the page. Good fits:
- An autosave or "copied to clipboard" confirmation that has no visible text, or only a brief icon change.
- A keyboard shortcut in an editor that does something invisible, like bolding text or moving a row.
- A drag-and-drop operation, where you want to report "Item moved to position 3 of 8".
- Filtering a list, where the useful information is the new count rather than the list itself.
filterInput.addEventListener('input', () => {
const count = applyFilter(filterInput.value);
results.ariaNotify(`${count} results`);
});
Don't use it to describe things that are already announced. If focus moves into a dialog, the screen reader reads the dialog's label on its own; adding a call on top just doubles the speech. Native controls such as dialogs opened with HTML invoker commands already handle their own announcements, so let them.
Also resist using "high" by default. Interrupting the user mid-sentence is the screen reader equivalent of a modal popup. Save it for errors and time-sensitive changes.
What are the gotchas?
Multiple calls may collapse into one. Some screen readers queue announcements in order, but many only speak the latest one. If you have two related messages, join them into one string.
// fragile: the first message may never be heard
document.ariaNotify('File uploaded.');
document.ariaNotify('3 files remaining.');
// reliable
document.ariaNotify('File uploaded. 3 files remaining.');
The same applies to rapid-fire events. In the filter example above, typing five characters fires five calls. Debouncing by a few hundred milliseconds keeps the user from hearing a stream of half-finished counts.
It fails silently when blocked. Usage is controlled by the aria-notify Permissions Policy. If a page or an iframe is not allowed to use it, the call throws nothing and announces nothing. If your widget runs inside a third-party iframe and seems mute, check the embedding page's policy first.
Element calls depend on the accessibility tree. You can call it on most elements, but browsers ignore elements they consider uninteresting for accessibility and leave out of the tree. Containers like <body> and <html> are safe choices. If an element call seems to do nothing, try it on the document.
No user gesture is needed. That makes it easy to misuse from timers and background updates. Announce what the user cares about, not every tick of a polling loop.
How do you use it with a fallback?
Support is recent, so feature-detect and keep a small live region for older browsers.
const fallback = document.createElement('div');
fallback.setAttribute('aria-live', 'polite');
fallback.className = 'visually-hidden';
document.body.append(fallback);
export function announce(message, { urgent = false } = {}) {
if ('ariaNotify' in document) {
document.ariaNotify(message, { priority: urgent ? 'high' : 'normal' });
return;
}
fallback.setAttribute('aria-live', urgent ? 'assertive' : 'polite');
fallback.textContent = '';
setTimeout(() => { fallback.textContent = message; }, 50);
}
The fallback creates the region at startup, so it already exists when the first message arrives. Clearing the text and setting it again after a short delay helps repeated identical messages get read. Once your analytics show the old browsers are gone, delete the fallback branch and keep the announce() signature.
Test with a real screen reader. VoiceOver on macOS and iOS, NVDA on Windows and TalkBack on Android each handle queuing a little differently, and the only way to know how your messages sound is to listen to them.
Key takeaways
ariaNotify()makes the screen reader speak a string directly, with no live region or DOM change.- It is Baseline as of September 2026: Chrome and Edge 141, Firefox 150, Safari 27.
priority: "high"interrupts current speech; the default waits its turn.- Combine related messages into one call, and debounce frequent events.
- A blocked Permissions Policy makes it fail silently, so check iframes first.
FAQ
Does ariaNotify() replace aria-live?
Not entirely. Live regions still suit content that is visible and changes on its own, like a status bar. ariaNotify() is better for announcements that have no natural place in the DOM.
Does ariaNotify() need a user click to work?
No. It does not require transient activation, so it works from timers, network callbacks and other async code. That is also why you should be careful about how often you call it.
Can sighted users see the announcement?
No. The text goes only to assistive technology. If sighted users need the same information, show it in the UI as well.