Routing
Single-page applications do not require a complete page reload when new page content loads. Ensure that users of assistive technology aren't excluded when we fail to provide the expected feedback and conventions.
Single-page applications (SPA) dynamically rewrite the current page rather than loading entire new page from the web server. This approach avoids interruption of the user experience between successive pages, making the application behave more like a desktop application. When implementing these dynamic page changes, it's important to should adhere to the conventions of page loading:
- The webpage's title should change to reflect the new content of the page
- Keyboard focus should move to the top of the page
Update page title
Screen reader software will read the page title first whenever a new page is loaded in the web browsers. The title helps users to identify the page they are on by having a concise, descriptive, and unique label for the page. [1]
You can update the title of a web page using JavaScript by accessing the document.title property and assigning a new value to it.
document.title = 'My New Page Title';
If there is a possibility of a delay as the new page content is downloaded and rendered, it's a good idea to keep the user informed by showing a loading spinner for example, and updating the page title with text like "Loading 'My New Page'...", before setting the title to it's fully loaded value of just "My New Page".
Move focus to the beginning of the page
In a non-SPA website, when a new page is retrieved and loads, the focus is automatically moved to the top of the page, on the HTML body element. Users who navigate by keyboard expect that they can then move down the page, for example using the tab key.
When a SPA displays new webpage content, most if not all of the previous content will disappear and new content will appear in its place, but the underlying HTML document does not reload and so the focused element is left in limbo. Focus must be moved programmatically to an element in the new page content before any other content, for example on to the HTML body element, as soon as the new page content appears.
function resetFocus() {
if (document.activeElement instanceof HTMLElement) {
document.activeElement.blur();
}
window.focus();
return document.activeElement;
}
console.log( resetFocus() ); // body
Another possible solution might be to move focus to the first HTML h1 element, assuming it is before any other content. This has the advantage of facilitating the reading out the content of the h1 element by the screen reader. It should be noted that you will need to set a tabindex attribute with a value of "-1" if you plan to programmatically move focus to a normally un-focusable element.
Managing history
Breaking the "Back" button is annoying to all users, but it can create serious barriers for users who rely on assistive technology and depend on conventions in UI to efficiently navigate.
In these cases you will need to maintain the expected navigational patterns by updating the browser history in Javascript using the History API. This allows you to store the different states of the application and return to them using the previous and next buttons of the browser.
Routing libraries like React Router make a useNavigate hook [2] available to facilitate working with browser history.
import { useNavigate } from 'react-router-dom';
function Redirect() {
let navigate = useNavigate();
const handleGoHome = () => {
navigate('/home');
};
return (
<button onClick={handleGoHome}>Go Home</button>
);
}
Checkpoints for the Tester
- For each of the possible pages (or page content states) ensure that a HTML page title is present which is unique, concise, and describes the primary page content.
- Ensure that the page title is announced by a screen reader when the new page content appears.
- Navigate to several pages of the website. Ensure that you can use the browser's "Back" and "Forward" buttons as expected to see the previous and next page content.
- Ensure that when new page content loads, and you then navigate using the keyboard only, that the keyboard focus starts at the very top of the page as expected.
Notes and references
Page Titles and A11y in Single Page Applications by Suzanne Aitchison back to reference 1
"Pass the delta you want to go in the history stack. For example,
navigate(-1)is equivalent to hitting the back button." React Router v6, useNavigate back to reference 2