# Your Single-Page App Changed Routes. Nobody Announced It.

Source: https://accessignal.com/blog/2026-11-13-spa-route-change-announcement.html

November 13, 2026

*A single-page app changes the route without loading a new page, so a screen reader user gets no announcement and no context for what just appeared. Move focus to the new page heading and announce the page title, and the route change becomes a page change.*

## The route changed; the screen reader stayed put

In a traditional site, every navigation loads a new document, and the screen reader announces the new page title. In a single-page app, the JavaScript swaps the content and updates the URL, and nothing announces anything. The user presses a link, the content changes, and the screen reader keeps reading from wherever it was, because as far as it knows, nothing happened. The visual user sees a new page. The screen reader user is still on the old one, listening to content that no longer exists.

This is the most common single-page app accessibility failure, and it is invisible to every scanner, because the DOM is technically fine. The heading exists, the landmarks exist, the links work. What is missing is the event: the announcement that a new page arrived and the focus move that puts the user at its start. Without both, navigation is a silent teleport.

## Focus has to move, and to the right place

When the route changes, move focus to [the new page main heading](2026-11-11-scanner-comparison-axe-wave-lighthouse-what-each-misses.md), the h1, and make that heading focusable with tabindex -1 so the move is legal. Do not move focus to the top of the page, because the top of the page is the header the user just left, and do not leave focus on the link that triggered the navigation, because that link may no longer exist in the new view. The heading is the right target because it is the first thing a sighted user reads, and the screen reader announces it on arrival, which gives the user the page title and their position in one move.

The heading needs tabindex -1, not 0, so it accepts programmatic focus without entering the tab order. A heading with tabindex 0 would add a tab stop nobody wants. Test the move with a keyboard alone: navigate, and check that the next tab goes to the first control of the new page, not to a leftover element from the old one. If focus lands somewhere unexpected, the route change is only half fixed.

## The announcement, kept short

Focus on the heading announces the heading text, which is usually enough. For routes where the heading alone does not say what changed, add a visually hidden live region that announces the page title on navigation, and keep it to the title alone. A long announcement about what the user can do on the new page is a lecture, not a notification, and it trains users to ignore the region. One sentence, the page title, then silence. The ARIA practices guide recommends exactly this shape: [a polite live region](2026-11-11-accessibility-alert-routing-owner-runbook.md), updated on route change, carrying the new page title.

Do not announce on every state change. A filter applied, a sort order changed, a cart count updated: those are status messages, and they belong in their own live region with their own wording. The route announcement is for navigation only. Mixing the two means the user cannot tell whether they arrived somewhere new or whether something on the current page changed, and the distinction matters more than the words.

## What to monitor

Monitor route changes the way you monitor deploys: after every release that touches routing, run the keyboard test on the three navigations users make most, search to product, product to cart, cart to checkout. Watch for the focus landing on a removed element, which throws focus to the body and leaves the user at the top with no announcement. Watch for the heading missing its tabindex -1 after a refactor, which silently breaks the move. And watch for the live region accumulating announcements, which means something is updating it on every render instead of on navigation. Each of these is a one-line regression with a one-line fix, and each of them is invisible until a screen reader user reports it, which is the point of monitoring it yourself first.

## Frequently asked questions

### Does a screen reader announce a route change by itself?

No. A single-page app route change updates the URL and swaps content without loading a new document, so nothing triggers the announcement a page load provides. The app has to move focus and announce the new title explicitly.

### Where should focus go after a route change?

To the new page main heading, with tabindex -1 so it can receive programmatic focus without entering the tab order. That gives the user the page title and the right starting position in one move.

### Should I announce the route change with a live region?

Yes, but keep it to the page title. Focus on the heading usually announces it already, so the live region is a backup for routes where the heading alone does not say enough. Do not announce instructions or descriptions.

### Can automation catch a missing route announcement?

No. The DOM looks correct either way, so scanners pass it. The test is manual: navigate with a screen reader running and listen for whether the new page is announced. Add it to the release checklist for any routing change.
