← Recipes

阅读中文版本

Manage Focus After SPA Navigation

Move focus to the new view heading on client-side navigation so keyboard and screen-reader users are not stranded.

~25 minfrontendaccessibilityspa

Task

Reset focus to the main heading after route changes in a single-page app.

When to use this

After a client-side navigation the focus stays on a link in the old view, confusing keyboard and screen-reader users.

Prerequisites

  • A single-page app with routing
  • Focusable headings or containers
  • A keyboard and screen reader for testing

Steps

1. After navigation, focus the new view heading.

router.afterEach(() => {
  nextTick(() => {
    const main = document.querySelector('main h1');
    if (main) { main.setAttribute('tabindex', '-1'); main.focus(); }
  });
});

Expected output: Focus moves to the new heading, so the next Tab continues in the new view.

2. Announce the page change to assistive technology.

<div aria-live="polite" id="route-announcer">{{ pageTitle }}</div>

Expected output: Screen readers announce the new page title after navigation.

Troubleshooting

Problem

Focus lost on redirects

Solution

Apply focus management after the final route settles, not on intermediate redirects.

Problem

Double announcement

Solution

Handle either focus or live-region announcement, not both for the same event.

Limitations

  • Focus to a heading is not universally understood.
  • Announcements may be delayed by the region.
  • Requires per-framework integration.

What this recipe does

Reset focus to the main heading after route changes in a single-page app.

After a client-side navigation the focus stays on a link in the old view, confusing keyboard and screen-reader users.

Prerequisites

  • A single-page app with routing
  • Focusable headings or containers
  • A keyboard and screen reader for testing

Procedure

  1. After navigation, focus the new view heading.
router.afterEach(() => {
  nextTick(() => {
    const main = document.querySelector('main h1');
    if (main) { main.setAttribute('tabindex', '-1'); main.focus(); }
  });
});

Expected result: Focus moves to the new heading, so the next Tab continues in the new view.

  1. Announce the page change to assistive technology.
<div aria-live="polite" id="route-announcer">{{ pageTitle }}</div>

Expected result: Screen readers announce the new page title after navigation.

How to confirm it worked

Run the commands above and confirm every expected result in order. If a step does not produce the stated output, use the troubleshooting notes before continuing. A passing run shows keyboard focus lands on the new view heading after navigation and screen readers announce the change.

Troubleshooting

Focus lost on redirects — Apply focus management after the final route settles, not on intermediate redirects.

Double announcement — Handle either focus or live-region announcement, not both for the same event.

Limitations

  • Focus to a heading is not universally understood.
  • Announcements may be delayed by the region.
  • Requires per-framework integration.