All Topics
Accessibility in JS Apps
Client-Side Routing

Client-side Rendering and Routing

Let’s focus on the unique aspects of JavaScript-heavy web apps, starting with client-side rendering and routing.

When you render your pages using libraries like React, Angular, Ember, Vue, etc., most of the UI is injected into the page with JavaScript.

Sometimes it is pre-rendered on the server and updated to client-rendering with hydration (opens in a new tab) (Next and Svelte do this, among others). Increasingly, frameworks and libraries will render from the server or at least give you the option (Astro).

Do people turn JavaScript off?

There’s been a debate over whether websites need to work without JS for a long time. Most of the internet requires it. But it is easier to render web apps on the server than it was a few years ago.

That said, the interactivity we’ve come to know and expect won’t be possible without JS. We can go back to some basics with forms and server-side actions, it’s true. But stateful ARIA and events need JavaScript to function.

What are the accessibility impacts of JavaScript?

Screen readers look at a page as-rendered, and they do use JavaScript. You don’t need to support non-JS to be accessible. But you do need to consider lower-bandwidth networks and older devices for people with disabilities. Many people can’t afford the latest tech for various reasons. This is an area where performance and accessibility intersect.

What is client-side routing?

When JavaScript handles routing from page to page, it takes away functionality from the web browser. Specifically, JS will replace one client-rendered view with another on demand without a page refresh.

This has impacts on keyboard focus and screen reader experience, as the typical page title announcements and focus reset won’t occur unless we replace them.

There are multiple techniques to handle client-side routing for accessibility:

  • Send focus to the main heading (with tabIndex="-1" on it) in the new content so it is announced and focus doesn’t remain on the old content.
  • Send focus to a wrapper element with the new content (also with tabIndex="-1" on it).
  • Mark up the new content itself with an ARIA Live Region so it’s announced on change and leave focus where it is.
  • Make an ARIA live region announcement on an .sr-only element and leave focus where it is.

I was curious which of these techniques was best for people who use screen readers, so I did some testing (opens in a new tab). It seemed like a combo of these techniques would work best. And that’s exactly my conclusion:

  1. Move focus to the new content to put users in the right part of the page.
  2. Make a Live Region announcement so the page change is explained.

You can read the full research study here, which has been referenced by most of the major JavaScript frameworks: https://www.gatsbyjs.com/blog/2019-07-11-user-testing-accessible-client-routing/ (opens in a new tab)

Codepen demo: https://codepen.io/marcysutton/pen/VwzdBQJ (opens in a new tab)

Real talk...real quick

Even though I did this research and I love to teach about Accessible JS, I’m actually not a fan of client-side routing.

It’s been half-baked and problematic in most implementations. I personally feel that multi-page apps are easier to maintain. Users also benefit from full page refreshes as they are configurable in screen readers, while custom client-side routing announcements are not.