Search topics
Auto-updating feeds that change while people read them
A news site's Latest list fetches itself again every 60 seconds and writes over itself, with nothing to turn it off, so the story people were on is gone.
list.innerHTML = await response.text(); The problem
People reading the list with a screen reader, a keyboard or a magnifier lose the story they were on every minute, and nothing lets them stop it.
A local news site, the Harbour Herald, has a Latest page: a numbered list of the day's stories, newest first, each with the time it was posted. So that the page never shows old news, a script fetches the list again every 60 seconds and writes it over the one on the page. For someone glancing at the whole list, new stories simply appear at the top.
Someone using a screen reader tabs down the headlines and stops on the third, "Library extends its weekend opening hours", to decide whether to open it. A minute after the page loaded, the list is written over. The link they were on is taken out of the page and a new copy put in its place, so focus falls back to the page itself and nothing says what happened. It happens every minute, even when no story has come in, because the links are new elements each time. At 10:43 a story about ferries comes in, and the library story moves down a place. Someone zoomed in on it with a magnifier sees it drop out of view and the bridge story take its place. Nothing on the page turns the updates off.
Success Criterion 3.2.5 Change on Request (Level AAA) asks that changes of context happen only when people ask for them, or that people can turn such changes off. WCAG's changes of context include moving focus somewhere else and significantly re-arranging the content of a page, because they can disorient people who can't see the whole page at once. Writing over the list does both. The main content is replaced by itself, and the focused link goes with it: when the element that has focus is removed, the browser moves focus to the page itself, and document.activeElement then returns the body. W3C names this failure F61, the content in the main viewport changed by an automatic update that people can't turn off, and its first example is a news site that refreshes itself to show the newest headlines. The sufficient technique for automatic updates, G76, gives people a way to ask for the update instead.
The browser has no reason to stop it. A timer runs whether or not anyone is reading, and innerHTML throws away every element it replaces, the focused one included, even when the new markup is the same.
The same list also falls under 2.2.2 Pause, Stop, Hide at Level A, since it updates by itself beside the rest of the page, and 2.2.2 asks for a way to pause, stop or hide such updates or to set how often they come. Both fixes below meet it too. A page that reloads itself on a timer, rather than rewriting part of itself, fails 2.2.1 first: pages that reload or redirect themselves on a timer covers that.
The update is made for people who look at the whole list and take in what is new. It costs everyone who moves through the list one story at a time, and the more slowly they move, the more often it catches them.
4 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 (affected)
- Reach, strength (not affected)
- Cognitive (affected)
- Seizures (not affected)
- Without vision A screen reader user moving down the headlines is on a link that the update takes out of the page. Focus falls back to the page itself, and where the screen reader goes on from is up to the screen reader, not to them.
- Limited manipulation Keyboard and switch users who have tabbed down to a story lose it each minute and have to work their way back to it, often to find the list has changed again on the way.
- Limited vision Under a magnifier only a story or two is in view, so when the list moves down one place, the story being read drops out of view and another takes its place, with nothing on screen to say why.
- Limited language, cognitive and learning abilities People who read slowly, or come back to the list after opening a story, find a different order each time and can't keep track of what they have already read.
There is nothing wrong in the markup, and a scan loads the page and leaves within seconds, long before the first update. The audit watches the timers a page starts by itself and sends one that fetches content and writes it into the page as markup to review, as ew:auto-refresh-manual-check: only a person can see whether it replaces the main content, and whether a switch before it turns it off. A meta refresh that reloads the page is axe's meta-refresh when the delay is under 20 hours; a longer one passes 2.2.1, and the audit sends it to review as axe:meta-refresh-no-exceptions. Asked to "keep the list up to date", AI coding tools can write the setInterval in the Before.
Try it
Tab to the third story in the list, then let the next update come in.
The list updates every 60 seconds, in real time; Skip to the next update on the demo clock saves the wait. Watch where focus goes and where your story ends up, then apply each fix and try again.
Broken Can you fix this?
The fix
Change the list only when people ask for it.
<section aria-labelledby="latest-title"> <h2 id="latest-title">Latest</h2> <ol id="stories"> <li> <time datetime="10:40">10:40</time> <a href="/news/storm-warning">Storm warning for the coast tonight</a> </li> … </ol></section>What is wrong4 points
- Every 60 seconds, the whole list is replaced, whether or not anyone is reading it.
- The focused story's link is removed with it, so focus falls back to the page.
- When a story comes in, every story below it moves down one place.
- Nothing turns the updates off.
A button that shows the new stories
<section aria-labelledby="latest-title"> <h2 id="latest-title">Latest</h2> <button type="button" id="show-new" hidden>Show 1 new story</button> <ol id="stories"> <li> <time datetime="10:40">10:40</time> <a href="/news/storm-warning">Storm warning for the coast tonight</a> </li> … </ol></section>How it is fixed4 steps
- Keep fetching every 60 seconds, but ask only for the stories newer than the first one on the page, and keep them aside instead of writing them into the list.
- Write how many there are into a button before the list, and show it. The list doesn't change, so nobody loses their place.
- When the button is pressed, add the new stories to the top of the list. This is the change people asked for.
- Move focus to the first new story, since the button they pressed is hidden again. They are now on what they asked to see.
This fixes the Before and passes 3.2.5: the main content changes only when someone presses the button. It also meets 2.2.2, since the list no longer changes by itself.
Why this fix: Change the page only when people ask
Both pass 3.2.5. The button is recommended: nothing changes until someone asks, so nobody has to find a setting first, while the checkbox is not enough on its own, because the updates still reach everyone who hasn't yet found it. The button costs one press for people who want the news as it comes; the checkbox suits a page whose readers mostly want it to keep up by itself, such as a live score, as long as the checkbox comes first and the choice is remembered.
Where focus goes. After the button is pressed it is hidden, and a hidden element can't keep focus, so the script moves focus to the first new story. Don't leave it for the browser to drop on the page. If the design keeps the button visible, focus can stay on it, with the count changed to "No new stories".
Saying that new stories are waiting. The button shows up silently, and that is enough for 3.2.5: people find it when they come back to the top of the list. If screen reader users should hear of it, write a short message into a role="status" region when the count goes from none to one, not on every check, or a message every minute becomes the next interruption. Countdown timers that screen readers keep reading out shows why.
A floating "new stories" pill. Some sites draw the button as a pill fixed to the top of the screen. Keep it before the list in the markup, so it comes before the stories in reading and Tab order, and make sure it never covers the story that has focus, as sticky headers and banners that hide keyboard focus describes.
Pausing while someone is on the list is not a fix. A script that holds the updates while focus or the pointer is inside the list still changes it the moment they leave, and a screen reader reading the list doesn't always move focus as it reads, so the script can't tell anyone is there.
Adding only the new stories at the top. Inserting the new items with insertAdjacentHTML('afterbegin', …) instead of rewriting the list keeps the focused link in the page, which is better than the Before. It still moves every story down under a magnifier while someone reads, so give people the button or the checkbox as well.
Pages that reload themselves. A Latest page with <meta http-equiv="refresh" content="300"> is the same failure by another route, and fails 2.2.1 as well. Delete the meta refresh, whatever its delay, and give people a button or a link that loads the new stories when they ask.
Live pages where the updates are the point. A live blog, a match page or a departures board exists to keep up, but 3.2.5 makes no exception for them. Give them the same button or checkbox; the people following a match closely will press it or leave the updates on.
Design ideas
A list can keep up with the news and still wait to be asked.
Three more ways to tell people new stories are in, and two fashionable ones that change the list by themselves. Tab to a story in each and wait a few seconds, then press what the sample offers.
In the design file
- Draw the list twice: with stories waiting, where only the control above it changes, and after it is pressed, with the new stories at the top.
- Put the button or the switch above the list, so it comes before the stories when the page is read or tabbed through.
- Write the count in words on the button, such as “2 new stories”, never as a dot or a number alone.
- Mark the first new story as the place focus goes once the button is pressed.
- If the page offers live updates, draw the switch off when the page opens.
Passes
- A count chip beside the heading A small soft chip, “2 new”, in the heading’s row, navy #1f3a5f on #e8eef6 at 9.84:1. It takes no room in the list, so nothing below it moves when it appears; pressing it adds the stories and puts focus on the first.
Rule of thumb: Change the page only when people ask
- Updated time with a Refresh button A quiet line, “Updated 10:40”, in #5f5f5f at 6.39:1, with a Refresh button after it. There is no count to keep fresh, and the time tells readers how old the list is; the list changes only when they press Refresh, and focus stays on it.
Rule of thumb: Change the page only when people ask
- A Live switch, off until turned on A pill switch labelled “Live updates” above the list, off when the page opens: a grey #6b6b6b track at 5.33:1, navy with a red dot when on. Readers who want the list to keep up turn it on; nobody else meets an update they didn’t ask for.
Fails
- Stories that slide in at the topWCAG 3.2.5 Tab to a story and wait: a new one slides in above it and pushes it down. It looks lively, but the story people were reading moves without being asked, and under a magnifier it leaves the view. The sample does it once; the pattern does it every minute.
Rule of thumb: Change the page only when people ask
Latest
Refreshing in 5An auto-refresh countdown ringWCAG 3.2.5 A thin ring counts down “Refreshing in 5”, then the whole list is drawn again, and a story that had focus is gone. The ring warns that the change is coming but gives no way to stop it. The sample counts down once; the pattern starts again after every refresh.
Verify the fix
5 checks, no mouse.
Test with: Keyboard, Screen reader, Zoom
Record the OS, browser and assistive-technology versions, the build, the date, and the actual result of each step. Repeat after the feed component or its update script changes.
Limits
This is a starting pattern, not a guarantee for every application. It covers a list that replaces itself on a timer. The other changes 3.2.5 asks people to start, such as a window that opens when a page loads or when text is typed, fail in the same way and take the same fix: let people start them. A field or select that changes the page when it is focused or changed is covered in dropdowns and fields that change the page on their own, and a link that opens a new tab in links that open a new tab without saying so. Screen readers differ in what they do when the element they were reading is removed: test with the ones your users have.
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: change-on-request (opens in a new tab)
- WCAG Technique F61 (opens in a new tab)
- WCAG Technique G76 (opens in a new tab)
- WCAG Understanding: on-focus (opens in a new tab)
- WCAG Understanding: pause-stop-hide (opens in a new tab)
- WCAG Technique F41 (opens in a new tab)
- amp.dev: amp-live-list (opens in a new tab)
EaseWeb service
Fixed it? Keep it from coming back.
I turn guides like this one into rules your coding agents follow and checks your CI runs. Then I retest by hand with a keyboard and screen readers, periodically.