Accessibility in standalone PWAs
Published
A standalone PWA excludes user-agent navigation controls, although the user agent may retain other UI such as a status bar. The app therefore has to supply operable navigation inside its own document, and it has to give each view a descriptive title. Structural landmarks and a visible focus indicator belong there too.
Start with the display mode
Section titled “Start with the display mode”The display-mode media feature reports which mode the app is shown in. browser is the ordinary tab; standalone, minimal-ui and fullscreen are the installed-app modes, and other supported values exist. MDN recommends minimal-ui when an app does not provide its own navigation elements because that mode can retain browser controls for moving between pages.
Display mode does not change WCAG requirements. WCAG 2.2 requires web pages to have titles that describe their topic or purpose, and requires a visible focus indicator in a keyboard-operable interface. WAI’s page-structure guidance recommends meaningful elements, headings, and labeled regions to support navigation and orientation.
Where it is supported
Section titled “Where it is supported”window.matchMedia('(display-mode: standalone)').matches is true in a standalone display context. When the query does not match, the document remains usable in its browser context; the Home link stays available in either mode.
Provide orientation and recovery paths
Section titled “Provide orientation and recovery paths”Give each route a descriptive <title> and use a logical heading hierarchy. Choose meaningful semantic elements and labeled regions that fit the page’s structure. In a standalone window, include links or controls that reach the app’s home and previous views; do not make browser chrome the sole recovery path.
Keep native link and button behavior, and preserve a visible keyboard focus indicator.
Examples
Section titled “Examples”The first example provides orientation inside the document. The second detects the display mode and adds a back control only when the app is running standalone.
Provide navigation landmarks and visible focus
Section titled “Provide navigation landmarks and visible focus”This fragment provides a title, a heading, a labeled navigation region, and a visible keyboard focus indicator.
<title>Account settings</title><a class="skip-link" href="#main">Skip to content</a><nav aria-label="App navigation"> <a href="/">Home</a></nav><main id="main" tabindex="-1"> <h1>Account settings</h1></main>
<style> :focus-visible { outline: 3px solid #075fcc; outline-offset: 3px; } .skip-link { position: absolute; left: -10000px; } .skip-link:focus { left: 1rem; top: 1rem; }</style>The home link works in every display mode. The skip link lets keyboard users jump past the repeated navigation.
Detect standalone mode with a browser fallback
Section titled “Detect standalone mode with a browser fallback”This fragment reveals a back control in standalone mode. When matchMedia is absent or the query does not match, it leaves the ordinary home link available instead of hiding navigation.
<nav aria-label="App navigation"> <a href="/">Home</a> <button id="back" type="button" hidden>Back</button></nav>
<script type="module"> const back = document.querySelector('#back'); if (!('matchMedia' in window)) { back.hidden = true; } else if (window.matchMedia('(display-mode: standalone)').matches) { back.hidden = false; back.addEventListener('click', () => { if (history.length > 1) history.back(); else location.assign('/'); }); } else { back.hidden = true; }</script>The back button appears only in standalone mode; everywhere else users still have the home link.
What goes wrong
Section titled “What goes wrong”After a single-page navigation, update document.title to describe the new view. The WAI guidance for Page Titled notes that distinct SPA views should update the title when their content changes.