Accessibility pitfalls in SPAs and programmatic fixes

SPAs lose native page-load cues, breaking screen reader context.
Cover route-change focus reset, ARIA live regions, semantic landmarks in dynamic markup, and keyboard trap prevention.
WHAT THIS TESTS: This tests whether you understand that Single Page Applications break the browser's default accessibility contract. In a traditional multi-page app, every route change triggers a full page load, which automatically resets keyboard focus to the top of the document and gives screen readers a clean context switch via a new page title and fresh semantics. SPAs hijack navigation and inject content dynamically, so none of that happens automatically. The interviewer wants to know if you can rebuild those missing primitives programmatically.
A GOOD ANSWER COVERS: First, programmatic focus management on every route change. This means explicitly sending focus to a meaningful target, typically an H1 or a skip link container with tabindex negative one, so keyboard and screen reader users land at the start of new content rather than remaining on the clicked link. Second, route change announcements for screen readers. Use an ARIA live region, usually aria-live polite, to announce the new page title or view name because screen readers do not automatically speak injected DOM the way they speak loaded documents. Third, semantic structure in dynamically rendered markup. Ensure landmarks like main, nav, and complementary regions persist, and that heading hierarchies are not flattened or duplicated across views. Fourth, keyboard trap prevention and focus restoration. Modals should lock focus with focusable element queries and restore focus to the trigger on close; routed views should not leave focus in detached DOM nodes.
COMMON WRONG ANSWERS: Claiming that React, Vue, or Angular handles accessibility automatically is a major red flag. Frameworks render DOM, but they do not manage focus or live regions without explicit code. Another red flag is suggesting a full page reload as the solution; the question asks for programmatic fixes within an SPA architecture. Proposing aria-live assertive for every route change is also wrong because it interrupts users and violates WCAG guidance on prioritization. Finally, ignoring the need for semantic HTML in favor of div soup with ARIA overrides shows shallow understanding.
LIKELY FOLLOW-UPS: How do you handle focus when a route change includes a modal or drawer? What is your strategy for preserving focus history when the user clicks back? How do you test these behaviors without relying solely on automated linting? The interviewer may also ask how you coordinate with designers to ensure focus indicators remain visible.
ONE CONCRETE EXAMPLE: Imagine a React Router application with ten routes. On each route change, you call a useFocusEffect hook that moves focus to an H1 with a ref and tabIndex of negative one. A visually hidden div with aria-live polite and aria-atomic true sits in the layout shell; when the route changes, you update its text content to the new page title, such as Dashboard or Settings, causing screen readers to announce the context shift. You verify with NVDA or VoiceOver that focus lands at the heading and the announcement fires before the user tabs into the new content.
Source: W3C WAI Curricula on Web Accessibility, Module 7: Rich Applications
Read the original → w3.org
- #accessibility
- #spa
- #aria
- #focus-management
- #screen-readers
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.