Accessible way to inform a screen reader of an ongoing dynamic content update by AJAX

The rise in the use of AJAX to dynamically update the content has resulted in accessibility problems for users of Assistive Technology such as Screen Readers.

The topic is not targeted only for single page applications. Many websites face similar issues e.g. loading the content clicking a "Load more" button, loading the tab content, modal content, pagination page change etc.

I am wondering about the public opinion of an accessible solution for the best possible user experience. Unfortunately the most relevant accessibility resources such as Google, ADG* and WebAIM did not provide the relevant answer.

The issues of dynamic content update instead of opening a standard page?

  • A screen reader user clicks the link and apparently nothing happens. It creates a poor user experience as the link might appear broken. The expectation was opening a new page and positioning to the top. A user is not aware that a part of the existing page is about to get updated soon. Screen readers do not announce content updates (except in specific cases)
  • A user focus remains on a link with no easy way of jumping to the updated content once the update was completed. There might be a bunch of other elements to skip. Clicking the link a user expects to access the content straight away

Solution requirements:

  • A user must be aware that a content loading has started if it takes longer than X seconds
  • A user focus must jump to the new content, preferably a heading element, after the update was completed

Disclaimer: Should such action use a link or a button?

The issue remains the same. It does not make a difference if a user clicked a link or a button. From my perspective it depends on the action whether we can assume it's more semantic to choose a button or a link. If the action simulates a new page load (most of the content on the page will change) then a user expects such behavior and thus a link is an element of choice. One might consider updating the page title too and handle the history state for "back" button in the browser. If the action will only replace one small part of the page e.g. collapsing/expanding element then a button might be a better option. In such cases focus jump might not even be a good idea despite the content update.


Easy part - The first part of the solution:

The first part of the solution is the second requirement.

The requirement "A user focus must jump to the new content" seems straightforward. I could use Javascript to move the focus to the heading element once the AJAX request was completed. In order to focus a heading which is otherwise non-focusable element it must have tabindex="-1" attribute.

Here are a few resources that lead me believing it's the right why. Also explaining why to focus a heading instead of focusing the entire container.

Video: Managing focus (focusing the heading element)
This is one of the rare cases where it's ok to remove the CSS outline (on heading)
Rob Dodson from A11ycasts

Two solutions to help non-sighted or keyboard-only users get to where they're going:
Emulate a native page load and move focus to the top of the document.
Move Focus on the content (heading or possibly form control).
daverupert.com - Accessible Page Navigation in SPAs

The most reliable way I found to overcome this challenge was to set the focus on the heading of the area that's changing
Marwan Aziz @medium.com - Accessibility considerations when building SPA

If the focus is set to an element, the screen reader announces it. This can be an easy way to inform users about something on the page: simply set the focus on it. Be sure though that this does not result in disorientation for the screen reader user: it shouldn't happen "out of the blue", but only when the screen reader user has done some interaction that caused the page change.
And by the way, you should not set the focus on a big container of information.
accessibility-developer-guide.com

The developer can simply allow the update to occur and not inform the user of it, alert the user of the update through some sort of embedded audio sound, or can set focus directly to the updated content.
WebAIM - Dynamic Content Updates

The user's focus is directed to new content added to the page.
Google Chrome DevTools - Accessibility Audit - Additional items to manually check


The second part - What if loading takes too long?

The second requirement is to inform a user that a content loading has started if it takes longer than X seconds. It makes sense as the user might be wondering why nothing happens after clicking the link. How would user know whether to wait or the link is simply broken?

What I tried so far?

  • BAD: Immediately move the focus to the heading placeholder of the new content where it suppose to appear. The initial heading text is "Please wait bla bla..." and it is being read immediately when focused. After testing with JAWS and NVDA in various browsers I decided against the solution because it simply wouldn't work as expected. Often after the new content was updated the screen reader was still reading "Please wait bla bla..." text and sometimes the new content was not read at all even though I moved the focus to the new heading again. Somewhat buggy
  • BAD: Show a loading modal dialog if a request takes longer than X seconds. User would be informed that a loading modal appeared and the modal title would be "Please wait bla bla...". After the content was updated the modal was closed and the heading of the new content was focused. This worked kind of ok but had lots of trouble with user experience. Opening the modal takes a while, especially when animated so it could happen that the modal opens after the content was already loaded making a confusion. Also in case when the screen reader was still reading "Please wait bla bla..." text sometimes the new heading would not be read after the modal was closed. Also a little buggy. On top of that I was just wondering does it make sense to display a modal for such case. It does not really seem user friendly
  • Maybe? The latest idea is to implement a status message container somewhere on the page which becomes visible when the AJAX request starts. The container has aria-live="polite" property and the text is "Please wait bla bla...". The focus would never be moved to the container so the user can remain on a clicked element until the request was done. Still the user would get informed that loading is in progress and in a polite way. I could also include a message to inform the user that the cursor will be positioned to the new content as soon as it's is available so that user can expect the focus jump. I am about to test it next week.

Opinions? Other ideas?