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.
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
- 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.
- 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.