Search topics
Countdown timers that screen readers keep reading out
A sale countdown sits in an aria-live="assertive" region, so a screen reader reads a new time after every line, or cuts the line off to say it, and nothing on the page stops it.
<p class="sale-banner" aria-live="assertive"> The problem
Screen reader users can't read the product page through, because a new time is read after every line or cuts the line off, and people distracted by the ticking have no way to stop it.
A linen shop is running an autumn sale, and every product page opens with a banner: "Sale ends in 02:14:09", counting down by the second. The developer wanted screen reader users to know the sale is running out, so the banner is marked aria-live="assertive".
A screen reader user opens a tea towel's page and reads the description, line by line. With JAWS, NVDA or Narrator, each line is read in full, and then the clock: "Hand-woven linen tea towel, washed for a soft feel from the first use. 02:14:06." The next line, then "02:14:03". If they stop to think, the times keep coming, one a second. With VoiceOver on a Mac or an iPad, the new time cuts the line off part way through, "Hand-woven linen, 02:14:08", and the rest of the line is never read. Either way, the description, the price and the Add to cart button are read in between clock times. A sighted visitor who finds the ticking numbers distracting has no way to stop them: the banner has no button, and it ticks for as long as the page is open.
The banner fails twice. The first failure is under 4.1.3. An aria-live="assertive" region asks the screen reader to present each change immediately, and ARIA lets it drop whatever was waiting. Understanding 4.1.3 says status messages should reach people "in a way that doesn't unnecessarily interrupt their work", and lists role="alert" or aria-live="assertive" on content that is not important and time-sensitive among its failures. The second that has just passed is neither. Screen readers don't all do what the region asks. In the 2026 releases, JAWS, NVDA and Narrator read an assertive region as they read a polite one, once the sentence or line in progress has ended, and VoiceOver on macOS and iPadOS interrupted. So every change is read, and where the screen reader honours the region, read over the page. The banner was never meant to be a status message: the script changes one number, and the region turns every change into an announcement.
The second failure is under 2.2.2. A countdown is auto-updating information: in the words of Understanding 2.2.2, content that updates based on a preset time interval. It starts by itself and sits beside the product, so WCAG asks for a way to pause, stop or hide it, or to control how often it updates, and there is no five-second allowance for auto-updating content. Understanding 2.2.2 also notes that such content "can also cause problems for screen readers", which is exactly what the live region turns it into here.
The banner is on every product page during the sale, so the times follow the visitor through the whole shop, and they stop only when the sale ends. On phones and tablets, most screen reader users use VoiceOver (70.6% of mobile respondents in WebAIM's 2024 survey), the screen reader that cut in on macOS and iPadOS in those tests.
2 of 10 groups affected
- No vision (affected)
- Low vision (not 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 (affected)
- Seizures (not affected)
- Without vision A new time is read after every line, and in VoiceOver it cuts the line off, so the product text, the price and the buttons can't be read through while the countdown runs.
- Limited language, cognitive and learning abilities Numbers that change every second at the top of the page pull the eye back again and again, and nothing stops them, so people with attention difficulties struggle to read the product beneath.
A scan sees a live region that is on the page from the start, with text in it, and passes it. Nothing in the markup says that the text changes every second. The audit watches the page for a few seconds before it touches anything. It reports text in an assertive region that changes by itself three times or more, and flags any text that keeps changing by itself, whatever region it is in, for a person to check, but it can't tell whether a Stop button elsewhere on the page controls it. AI assistants asked to make a countdown accessible may add aria-live to it, which is what produced this banner, or role="timer" together with aria-live="assertive", which brings the interruption back. Only listening to the page while the countdown runs shows the problem, and what it sounds like depends on the screen reader.
Try it
Press Read next line, as a screen reader user presses the Down arrow, and read the product while the sale counts down.
The clock starts when you start reading. The panel shows what the screen reader says, as JAWS, NVDA and Narrator read it; on the page, the words read so far are highlighted. What comes after each line? Switch to VoiceOver to see it cut the lines off, and look for a way to stop the clock.
Broken Can you fix this?
Linen tea towel
Hand-woven linen tea towel, washed for a soft feel from the first use.
Each towel is woven on a narrow loom, so the edges never fray.
Machine wash at 40 degrees, and dry on the line.
$18 each, or three for $45 during the sale.
Screen reader says:
(Press Read next line)
The fix
Show the end time, or keep the countdown silent with role="timer" and a button that stops it.
- 1Never put a clock, score or counter that changes by itself in an assertive live region.
- 2Give text that changes by itself a button that stops it, or show a fixed time instead.
- 3Say the time left at most at a milestone, once, in a status region.
<p class="sale-banner" aria-live="assertive"> Sale ends in <span id="sale-clock">02:14:09</span></p>The end time, written once
<p class="sale-banner"> Sale ends <time id="sale-end" datetime="2026-10-31T23:59:00Z">31 October at 23:59</time></p>Why this fix: Let people stop anything that moves by itself
The script changes the number every second, inside a region that is assertive, so the changes are announced: after each line in JAWS, NVDA and Narrator, and over the line in VoiceOver. There is nothing on the page that stops it.
Nothing changes after the page loads, so there is nothing to announce and nothing to stop, and 2.2.2 has nothing to ask for. The banner has no live region: a screen reader reads "Sale ends 31 October at 23:59" once, when the person reaches it, as it reads any other line. The time element carries the exact moment in datetime, and the script rewrites the visible words in the visitor's own time zone, so they don't have to work out the difference. The banner loses its ticking, which some shops use to make a sale feel urgent.
Both pass 4.1.3 and 2.2.2. The end time costs nothing to build, reads once for everyone, and gives nobody anything to stop, but it gives up the ticking. The silent countdown keeps the ticking, at the cost of a button, a little more script and a banner that moves for everyone until they find the button. Choose the end time when the shop can do without the ticking, and the silent countdown with its button when the ticking is part of how the sale is sold.
Polite is not a fix. Changing the region to aria-live="polite" stops VoiceOver cutting into a line, but every screen reader still reads a new time after every line, so the page is read in between times. That is what JAWS, NVDA and Narrator already do with the assertive one. Understanding 4.1.3 warns that live regions and alerts risk making an application too "chatty" for a screen reader user. For a countdown the answer is the same as for the assertive one: no live region on the clock.
role="timer" keeps it quiet. A timer is a live region whose aria-live is off by default, so its changes are not announced. Don't add aria-live to it: role="timer" aria-live="assertive" is the Before again. Removing aria-live and leaving the role out would also stop the announcements; the role tells assistive technology what the changing number is, and some screen readers announce its name before its contents.
Say a milestone, once, if it matters. People rarely need to hear that a sale is nearly over. When they do, as with a booking held for a few minutes, write one message into a role="status" region at a milestone ("10 minutes left"), and keep the clock silent. MDN's timer example switches the timer's own role to alert at ten seconds; a separate status region announces the milestone once, without making the clock a live region at all. A time limit on the person's own task is a different failure, covered in session timeouts with no warning or way to extend.
Keep the choice. Store the stopped state, for example in sessionStorage, so the banner doesn't start ticking again on every product page the visitor opens.
Hide is allowed too. 2.2.2 accepts pause, stop or hide. A Close button that removes the banner passes, but it takes the sale's end with it, so pair it with the end time somewhere else on the page.
Scores, feeds and prices. The same failure shows up wherever something changes by itself, and the fixes follow the same lines.
- A live score: the match clock in
role="timer"or no live region at all, and the score written into arole="status"region only when it changes ("Goal: Rovers 2, City 1"), with a button that pauses the updates. - A live blog or news feed: new entries added to a
role="log"region, which is polite, and a Pause updates button, since a feed that grows on its own is auto-updating content too. - Prices and stock levels that refresh: no live region on the numbers, and a button or setting that stops the refresh or makes it less frequent.
Moving and urgent are other topics. A ticker that scrolls sideways is moving content, with its own fixes in tickers, carousels and animations that can't be paused. When a message really is urgent, role="alert" is right, and choosing between the two is covered in alerts that cut off VoiceOver for routine updates.
Fixing this with an AI coding assistant? Get this guide as Markdown, or get every guide in your coding agent.
Design ideas
A sale’s end has more than one look.
Five more ways to show when the autumn sale ends, in the shop’s own colours. Three tell people the time without ticking; two keep changing by themselves, and nothing beside them stops them.
In the design file
- Write when the sale ends as a date and a time, wherever the design would show a countdown.
- If the design keeps a ticking countdown, draw a Stop countdown button before it, and the banner once it is pressed, with the end time in place of the clock.
- Mark the countdown as never read aloud as it changes, since a screen reader reads it once, when someone reaches it.
Passes
- End-time pill A soft pill with a calendar icon, the day and the time. Nothing changes after the page loads, so there is nothing to stop, and a screen reader reads it once, like any other line.
- Days-left bar “2 days left” over a thin bar of the sale so far. It is set once, when the page loads, and never moves while it is open; the words carry the number, so the bar needs no live region.
- Last-day ribbon A ribbon that appears only on the final day, with the closing time in it. The urgency comes from the word “last”, not from a clock, and it changes at most once a day, when a page is loaded.
Fails
- Flip-clock countdownWCAG 2.2.2 Each second flips over like a station board, which is lively, and it never stops: there is no button to pause, stop or hide it. The sample stops after four flips; the pattern does not.
Rule of thumb: Move to show a change, then stop
- Minutes-only countdownWCAG 2.2.2 “Sale ends in 2 h 14 min” looks calm, but it still changes by itself, once a minute, beside the product, and 2.2.2 gives auto-updating content no allowance for being slow. It needs the same Stop button as a clock that ticks by the second.
Rule of thumb: Let people stop anything that moves by itself
Verify the fix
4 checks, no mouse.
Test with: Screen reader, Keyboard
Record the OS, browser and assistive-technology versions, the build, the date, and the actual result of each step. Repeat after the banner, its script or the sale component changes.
Limits
Live regions behave differently across screen readers and browsers, and from one version to the next: what this guide describes is how the releases current in 2026 behaved. Understanding 4.1.3 also notes that, depending on the user's preferences, assistive technology may delay, suppress or transform status messages. This guide covers a countdown beside other content, on one page. Whether the updating is essential to an activity, as an auction's clock may be, is a judgement for the team, and 2.2.2 does not ask for a way to stop it then; even so, the clock does not need to announce every second. Test 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.
References
- WCAG Understanding: status-messages (opens in a new tab)
- WCAG Understanding: pause-stop-hide (opens in a new tab)
- WCAG Technique G186 (opens in a new tab)
- w3.org: wai-aria-1.2 (opens in a new tab)
- developer.mozilla.org: timer_role (opens in a new tab)
- developer.mozilla.org: aria-live (opens in a new tab)
- developer.mozilla.org: time (opens in a new tab)
- webaim.org: screenreadersurvey10 (opens in a new tab)
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.