Accessible Routing in JavaScript Frameworks
Lost in Transition
In my role as a Developer Consultant with Deque, I get asked a variety of questions on how to implement and fix technical accessibility issues. One topic that always seems to be at the forefront of everything else that developers have asked is ‘How do I manage focus in my JavaScript framework?’. This question is not just limited to developers though, as I have been asked this question from designers and project managers as well. As simple a question as this may sound, this is actually a pretty loaded and complicated question.
The first thing that’s important to understand in order to fully grasp this issue is why it is an issue in the first place. Compared to the traditional web, where navigating different pages of the site would cause a reload of the browser each time, JavaScript frameworks such as React, Angular, and Vue do not actually refresh the DOM. Instead, when navigating (or routing) in JavaScript frameworks, the content is dynamically added in and swapped out, making it seem like a page has been changed.
Therein lies the problem; to a user who is using assistive technologies such as NVDA or JAWS, the focus becomes lost or stagnant on the page and the user is not made aware that a new page has appeared. This can leave a user feeling confused or lost on your page as they may think the link did not work OR they may leave your site entirely because it is extremely difficult to navigate. Assistive technology users are not the only ones in trouble here, as keyboard-only users can also become very frustrated because focus is not managed, forcing them to traverse back to the new content that has appeared on screen.
Now that you understand the issue, how do we fix the problem? There are a couple of different solutions that can work well to fix this issue, but we need to look at it from a designer’s and a developer’s perspective.
Developer Perspective
The solution to the above problem actually has a couple of different avenues depending on how your application is set up. The solutions listed below would be the recommended fixes in order of the best solution to the bare minimum to make the transition of pages work.
Move focus to the first heading on the new page content
Once a new page is loaded, the focus should go to the most relevant heading of the new page. Preferably this would be the top-level heading (<h1>,<h2>). This can be achieved by adding tabindex= “-1” to the heading and using the component lifecycle of the JavaScript framework you are using and JavaScript to assign focus to the top-level heading.
Move focus to the body of the page
If you do not have a relevant heading on the page that a user is transitioning to, another way to manage focus is to put focus on the body. This would try to give a similar experience to a site that would reload every page change. To achieve this, you would have to add tabindex= “-1” to the body or main container and then manage focus via JavaScript or component lifecycle.
Move focus to a skip to main content link with a live announcement that page has changed
Last but not least, if the top two solutions are not available and you have a skip to main content link on your site, then move focus to the skip to main content link.
With this, also have a live announcement be made to the user that the page has changed, or the new name of the page so they know the page has changed. This allows a user to know that the page has changed and they can then jump directly to the new page content using the skip to main content link.
Design Perspective
When working with a JavaScript framework, there are some design choices to consider in order to properly get page transitions to make sense for all users. Here are some considerations below:
Make sure each page has a proper heading, preferably <h1> or <h2>
By ensuring that each page has a proper heading on it, developers can then properly put focus to the heading for page transitions. In addition, the heading should be descriptive enough to understand the page’s purpose as well.
Include what should happen between page to page transitions
If possible when designing content, and if you know that the development will be done in a JavaScript framework, include what should happen when transitioning to a new page. This will help developers understand where focus should be placed when the page is fully transitioned.
Make sure visible focus is available on the body of the page if needed
If there is no relevant heading on the page, or it is not an option to put focus on the heading and you have to put focus on the body of the DOM, then a focus indicator must be present so users can know where the current focus is.
In Summary
As simple of an issue as focus management between pages on your site may seem, you can now see the large implications it can have on the accessibility of your site. Unfortunately, the trend lately has been that there is less and less focus management with sites created using JavaScript frameworks.
With the popularity of JavaScript frameworks increasing alongside that, it makes for sites that are extremely inaccessible. However, if you can follow the above suggestions and design guidance within your application, then we can reverse the trend and once again make dynamic sites that are fully accessible!
I don’t think advising developers to place the focus on the H1 heading is the right thing to do. If there is content before the H1 main heading then users are likely to miss that content. So many websites these days have a hero image with important text placed on it, or other content before the main heading. Some sites do this only on the Home page, others do it on all or most pages.
So much better, I think, to advise developers to place focus on or just before the element so users get to see all the page-specific content. Or even at the top of the page before the Skip to Content link, so it looks like a normal website page to the user.
That last comment should have read ‘better……to place focus on or just before the “main” element…..’ (I put the “main” in the usual angle brackets and the comments system treated it as HTML!)