Search topics
Status messages that are shown but never announced
A "Draft saved" toast is created together with its message, so the browser never sees a change to announce, even with aria-live on it.
The problem
Screen reader users don't hear that their work was saved, or that saving failed, because the message appears without ever being announced.
A notes app saves a draft a moment after you stop typing. When it saves, a small toast slides in at the bottom of the page: "Draft saved". Three seconds later it is gone. A sighted user glances at it and carries on. A screen reader user types a paragraph, pauses, and hears nothing. They don't know whether the draft was saved, whether it is safe to close the tab, or whether the save failed, so they look for a save button that isn't there, or copy the text somewhere else to be safe.
The developer did add aria-live="polite" to the toast. It still says nothing.
"Draft saved" is a status message: it reports the result of something the person did, without taking focus. Success Criterion 4.1.3 asks that such messages can be presented to assistive technology through role or properties, so that they are announced without moving focus. A live region does that, but only for changes the browser sees inside a region it already knows about. Here the script creates the toast element, its text and its aria-live in one step and appends it to the page. To the browser that is a new region arriving with its content, not a change to an existing one, and most screen readers stay silent. The visible message and the spoken one have come apart.
The toast is placed for someone looking at the whole page, so anyone who isn't, because they are listening or because they are zoomed in on the text they are writing, misses it.
2 of 10 groups affected
- No vision (affected)
- Low vision (affected)
- Colour vision (not affected)
- No hearing (not affected)
- Hard of hearing (not affected)
- No speech (not affected)
- Motor (not affected)
- Reach, strength (not affected)
- Cognitive (not affected)
- Seizures (not affected)
- Without vision Screen reader users never hear that the draft was saved, so they can't tell whether it is safe to leave the page, and they don't hear when saving fails.
- Limited vision Screen magnifier users zoomed in on the editor rarely see a toast in the corner of the page, and it is gone before they could pan to it.
A scan finds aria-live on the toast and passes it; it can't tell that the region was born with its message. A scan of the page when no toast is showing sees no region at all. AI assistants often write exactly this pattern, because the attribute is present and the code looks complete. Others move focus to the toast so that it is read, which pulls the caret out of the text in the middle of a sentence. Only a screen reader, used while typing, shows whether anything is said.
Try it
Type in the note, stop, and listen.
The panel shows what a screen reader announces when the draft is saved. Is "Draft saved" ever heard?
Broken Can you fix this?
Screen reader says: (Type in the note, then stop)
A recreated demo. The broken version is intentionally inaccessible.
The fix
Change the text of a status region that was on the page before the message.
- 1Render the status region, or the toast container, empty with the page; change only its contents.
- 2Use role="status" for routine news; keep focus where the person is working.
- 3Put the result in words, including when saving fails.
<label for="note">Note</label><textarea id="note"></textarea>Why this fix: Show a message next to what it is about
The region and its words arrive together and leave together, so the browser never sees the text change inside a region it was watching. The message is on screen, and never announced.
The p with role="status" is in the HTML from the start and empty, so the browser is watching it when its text changes. The screen reader finishes what it is saying, then reads "Draft saved at 10:42." The caret stays in the text. The line stays under the editor, where both a magnifier user and a sighted user are already looking, and the time tells people the save is recent.
Both announce "Draft saved" without moving focus. Use the status line beside the editor: it is the same amount of code, and it gives up nothing, because the message also stays where people are looking and doesn't vanish before a magnifier user can find it. The toast container is the right choice when a site already shows its messages as toasts and changing that is out of reach; it fixes every toast at once. With toasts, give people enough time to read them, and keep anything they must act on out of them.
The region must exist first. In a component framework, render the region in the layout or in the editor's own markup, never inside an {#if} or a conditional render that appears with the message. A region added with its message is the same failure in different code.
Hidden regions don't speak. A live region inside display: none, visibility: hidden or aria-hidden="true" is not announced, and in some browsers a region that was hidden and is then shown along with its text is treated as new. To hide the status line visually and still have it read, use a visually hidden class, not display: none.
The role is the live region. role="status" already means aria-live="polite" and aria-atomic="true". A div with aria-live="polite" aria-atomic="true" and no role works the same way. Don't add aria-live="assertive" or role="alert" to routine saves; it cuts into what the person is listening to every time they pause.
Say it at the right moment. Announce after a save finishes, not on every keystroke, and not "Saving…" every few seconds. If the same words are written twice, some screen readers stay silent the second time; the time in "Draft saved at 10:42" changes the text, or clear the region before writing.
Failure needs words too. "Draft not saved" is a status message as well. If people lose work when they leave, also show it next to the editor until saving works again.
A close button. A toast can have a button to dismiss it, but a button inside the live region may be read with the message ("Draft saved, Dismiss"). That is acceptable: keep its name short. Don't give the toast a live region of its own to avoid it; that brings back the failure in "Before". Don't rely on the button alone to remove the toast: it should still go by itself after enough time to read it.
Not fixes. Moving focus to the toast does get it read, but it takes the caret out of the text, and it is not what 4.1.3 asks for. The <output> element maps to the status role, but screen readers announce its changes less reliably than an explicit role="status".
Fixing this with an AI coding assistant? Get this guide as Markdown
Verify the fix
4 checks, no mouse.
Test with: Screen reader, Keyboard, Zoom
Record the OS, browser and assistive-technology versions, the build, the date, and the actual result of each step. Repeat after the toast component or the page layout changes.
Limits
Live regions behave differently across screen readers and browsers, especially for regions that are moved, hidden or inside dialogs. This pattern covers one kind of message on one page. Loading, search results, form results and urgent alerts are topics of their own. Test your real messages with the screen readers your users use.
This is a recreated teaching example, not a finding about a named client. The code is a starting pattern: test it in your own product. No completed assistive-technology test is claimed here.
Keep this fixed as your code changes.
Turn guides like this into rules your coding agents and CI follow, then have the result retested with a keyboard and screen readers.