It is important to keep in mind that some visitors to your site rely on screen readers, so you should ensure that they have a pleasant experience. One "issue" with single-page applications is that they traditionally are more difficult for screen reader users because they do not have a great way for detecting navigation.

Curi provides a couple approaches to help you make your site accessible.

Announcing Navigation

When the content of ARIA live regions change, the new content will be announced to screen reader users. The announce function exported by the @curi/router package is a side effect for creating a live region and updating its content to announce navigation.

The side effect takes a function which returns a string that should be read by screen readers. This can be whatever you want it to be, but screen readers normally read a page's title, so if you are setting meta.titles for your responses, it is probably a good idea to have those announced.

import { announce } from "@curi/router";

let routes = prepareRoutes([
    name: "Home",
    path: "",
    respond() {
      return {
        title: "Home"

let router = createRouter(browser, routes, {
  sideEffects: [announce(
    ({ response }) => `Navigated to ${response.meta.title}`

// when the user navigates to "/", the screen reader
// will read: "Navigated to Home"

Focusing Content

Screen readers read the content of elements in the page that are focused. They can move through the page to read different elements. When you navigate, the content of the site will be re-rendered, so it is important for you to focus on the new content so that users using screen readers don't have to tab around looking for the new content. This is focus management and there are a couple things to keep in mind when implementing it.

When you focus an element, make sure to focus the specific content for a page. If you were to just focus the page's <body> or a root <div>, then the user might have to tab through less important content, like the page's menus, while looking for the new content.

  it is better to focus the important content (<main>)
  and not the entire page

The element that you focus needs to be focusable. Elements can be natively focusable (e.g. <input>s and <a>s) or you can use the tabIndex property. A tabIndex of -1 lets you focus an element, but keeps screen readers from accidentally focusing it when a user is tabbing through the page's contents.

<!-- you can focus us -->
<input />
<a href="">Example</a>
<main tabIndex="-1"></main>

<!-- but not me -->

Focusing in React Applications

The @curi/react-dom package provides a useNavigationFocus hook that gives you a ref to attach to the component that should be focused. Whenever the user navigates, it will re-focus so that the screen reader is focused on the correct content.

import { useResponse, useNavigationFocus } from "@curi/react-dom";

function App() {
  let { response } = useResponse();
  let ref = React.createRef(null);

  let { body:Body } = response;
  return (
    <Header />
    <main ref={ref} tabIndex={-1}>
      <Body />

Focusing in Vue Applications

The @curi/vue package provides a directive for focusing an element. The directive needs to be passed something that changes when the user navigates, so you can pass it the current response.

  <main tabIndex="-1" v-curi-focus="$curi.response">
    <component :is="$curi.response.body" />

More Resources

The above content is great for making navigation within your application accessible, but those aren't the only steps that you should take to making your site more accessible.

If you are interested in other resources for improving the accessibility of your website, I would recommend Google's collection of accessibility articles. WebAIM also provides a good checklist to consult.

The ChromeVox extension for Chrome is a free screen reader that you can use to experience your site like a user using a screen reader would. This documentation site uses the above announcement and focus techniques, so you can see how they work by activating a screen reader and navigating throughout this site.