Description
The Problem
Single page applications (SPAs) made our apps faster, because we no longer had to reload all of the content every time, thanks to pushState
. However, pushState
purposefully came with no event hook, and the thinking was that developers should manually manage focus (see the IRC logs from that time, and I’ve spoken with some of the folks who were involved with the decision when it was made).
We also respect the traditional URL, which made the experience feel like browsing on a static site- for all users except ones that need assistive technology.
There are well-known issues that users with assistive technology have when it comes to client-side routing:
- Because there is no full-page refresh, the user has no way of knowing that the page has changed at all.
- Because there is no focus management, the user’s focus remains where it is.
- In cases where the item that had focus goes away, focus is lost.
- In the cases where the item that has focus doesn’t go away, the focus simply remains where it is (and if you imagine the user interacting with a link in the footer, and then they experience silence- and their focus still stays on that link in the footer- well, that’s a bad experience. Makes it feel like something is broken.
So we have two distinct issues:
- Lack of focus management
- Lack of feedback that a page transition has occurred
Current Solutions
See: Solution Comparisons in JS Frameworks
From what I am aware of, current solutions use one or more methods to resolve the issue:
- Dynamically set the focus on a wrapper element
- Dynamically set focus on a heading element (h1-h6) to move focus to the new content
- Dynamically set focus to an interactive element such as a skip link
- Use an aria-live region announcement
- Imitate a traditional browser refresh by resetting focus
Thinking About A Permanent Solution
I wonder if ARIA could provide some type of support (a role, perhaps?) that authors could use to indicate "here's where the new content will be loaded when the route(URL) changes."
Another potential solution is some sort of new event hook- something that indicates that a semantic navigation event has occurred. (Vaguely, imagine something like pushState
but also have a second parameter with a promise that resolves with a DOM node.) Both frameworks and assistive technology could use this event to indicate/recognize new content.
It's also possible that this is a problem for SPAs to solve on their own, without any other involvement from any spec.
Research
Here is some extra reading that might be useful; it's documentation of my own experiments to try to find a potential solution, with links to test apps that demonstrate some ideas - https://github.com/MelSumner/ember-a11y-roadmap/blob/master/rfc-research/router/ideas-and-experiments.md