Progressive web apps and accessibility:
the state of the art in 2026
Six years after Apple finally shipped a working install path on iOS 16.4, the progressive web app has stopped being a curiosity and started being a procurement question. This primer is for engineering teams who need to know, in 2026, what a PWA actually owes its assistive-tech users — and where the platform still falls short of a real native app.
1. What “PWA accessibility” means in 2026
A progressive web app is, at runtime, three things layered on top of a normal website: a Web App Manifest, a service worker, and an installed-mode chrome that replaces the browser frame with the operating system’s own task-switcher entry. Each of the three layers introduces its own accessibility obligations — and each fails its assistive-tech users in a different, separately-debuggable way.
In 2020 the entire conversation collapsed into “WCAG applies to PWAs,” which was technically correct and operationally useless. In 2026 the conversation is split into the four surfaces that actually matter: the install-prompt UX, the manifest properties that drive OS-level affordances, the handoff between the browser’s accessibility tree and the operating system’s accessibility tree once the PWA is launched in standalone mode, and the assistive-tech behavior of the service-worker offline fallback. WCAG 2.2 governs the document; the platform-integration layer is governed by a much patchier mix of W3C drafts, vendor-specific behavior, and ARIA conventions inherited from the web.
This primer covers the platform-integration surface of PWAs — install prompts, manifest properties, standalone-mode AT behavior, offline fallback. It assumes the underlying document already meets WCAG 2.2 AA. A PWA wrapper on top of an inaccessible page is still an inaccessible page.
2. The install prompt
The install prompt is the most user-facing PWA surface and, in 2026, still the worst-engineered one. On Chromium, the prompt is gated by beforeinstallprompt, which fires only after a heuristic engagement threshold and which sites typically wire into a custom “Install app” button. That custom button is where accessibility goes wrong: roughly one in three Lighthouse-scoring PWAs renders the install affordance as a <div> or a styled <span> with no role, no accessible name, and no keyboard handler — invisible to a screen reader, unreachable by Tab, and indistinguishable from decorative chrome.
The fix is unglamorous and mandatory: render the install affordance as a real <button>, set an accessible name that includes the verb (“Install Disability World on this device”), expose the same button to all input modalities, and announce success or failure via a live region after the user dismisses the OS-level confirmation sheet. The same applies to the related-applications and beforeinstallprompt dismissed states — both must produce an AT-perceivable status change.
<div onclick="install()">Install</div>— not focusable, no role, screen reader sees only the word “Install” with no actionable affordance.- Button hidden until
beforeinstallpromptfires — keyboard users land on a stale “Install” link that does nothing after the event. - No status announcement after dismissal — the AT user has no way to know whether the install succeeded.
<button type="button" aria-label="Install Disability World">...</button>with explicitaria-disabledwhen the install isn’t yet available.beforeinstallprompthandler stashes the event; the button reflects the resulting state viaaria-disabledtoggled on event arrival.- A polite live region announces “Installed” or “Install dismissed” after
userChoiceresolves, so the AT user has a perceivable confirmation.
3. The manifest surface
The Web App Manifest grew quietly between 2022 and 2026, and many of its newer properties carry direct accessibility consequences. The matrix below maps the eleven manifest properties that interact with assistive technology to what each browser actually does with them today — across Chrome on Android, Safari on iOS, Edge on Windows, and Firefox on desktop. Properties such as file_handlers, share_target, and window_controls_overlay did not exist in any meaningful form in 2021; in 2026 they shape whether the PWA appears in the OS share sheet, opens files from the system file manager, and renders its own titlebar — all of which the screen reader user must be able to perceive and operate.
| Chrome (Android) | Safari (iOS 16.4+) | Edge (Windows) | Firefox (desktop) | |
|---|---|---|---|---|
name exposed to OS launcher | Yes | Yes | Yes | N/A |
short_name shown under home-screen icon | Yes | Yes | Yes | N/A |
description read by AT in app-info dialog | Yes | Partial | Yes | N/A |
Adaptive maskable icons (purpose: "maskable") | Yes | No | Yes | N/A |
lang + dir propagate to AT | Yes | Partial | Yes | N/A |
file_handlers — open from system file manager | Yes | No | Yes | N/A |
share_target — appears in OS share sheet | Yes | No | Yes | N/A |
window_controls_overlay titlebar takeover | N/A | N/A | Yes | N/A |
shortcuts — long-press launcher menu | Yes | No | Yes | N/A |
display_override (minimal-ui, window-controls-overlay) | Yes | No | Yes | N/A |
launch_handler (focus-existing) | Yes | No | Yes | N/A |
window_controls_overlay trapWhen a PWA opts into window_controls_overlay, it takes over the OS titlebar — including the region where, on a native app, the screen reader would announce the window title automatically. Apps that adopt this property must explicitly render their own focusable, AT-labeled titlebar control inside the safe-area inset, or screen-reader users lose the only on-screen anchor for “where am I in this app.”
4. The web ↔ native screen-reader handoff
The single hardest debugging problem in PWA accessibility, in 2026, is what happens when the user crosses the seam between standalone-mode PWA chrome and the operating system itself. On Android, TalkBack reads the manifest name when the user focuses the home-screen icon, then transitions to reading the in-app accessibility tree once the PWA launches; on iOS 16.4+, VoiceOver does the same for an installed PWA but with one important quirk — the first focusable element after launch is announced without the app-level context that a native iOS app would supply through its UIWindow title.
The PWA author has one tool to bridge this gap: on cold launch, focus a heading or main-region landmark that includes the app name in its accessible label, and set the document <title> to a string that the OS task switcher will read when the user swipes between apps. Without this, the screen-reader user loses the contextual cue that they have switched applications — a “where am I” failure that doesn’t exist for native apps.
”In 2024 a Bluetooth-keyboard VoiceOver user told us, on a PWA we had certified to WCAG 2.2 AA, that they had no idea they had switched out of Safari and into our app. The document was accessible. The handoff was not.”
5. Offline + assistive-tech behavior
When the service worker serves an offline fallback page, two AT-specific failure modes appear: the focus that was inside the now-unloaded page is silently dropped onto the document body, and the offline page itself rarely uses a live region to tell the screen-reader user what just happened. The result is a user who hears one announcement of the offline-page title (if they’re lucky) and otherwise experiences a total loss of context.
The fix is to treat the offline transition as a state change, announce it through a polite aria-live region, restore focus to a known landmark on the offline page, and surface a “Retry” control as a real button rather than the “Reload” link most service-worker boilerplates ship. The same applies to the foreground-sync recovery path: when connectivity returns and the service worker drains the queue, that too is a state change the AT user must be told about.
Polite live region announces “You are offline” on transition. Focus is moved to the offline-page main heading. A clearly-labeled <button>Retry</button> is the first interactive element. On reconnection, a second polite announcement says “Connection restored” and focus is restored to whatever the user was last interacting with.
6. iOS Safari vs Android vs native
The “should we ship a PWA or a native app” question now has an accessibility dimension as well as a feature-completeness one. Below, we compare the same hypothetical news-reader app delivered four ways — as a PWA on Android, as a PWA on iOS 16.4+, as a native iOS app, and as a native Android app — across the five surfaces a screen-reader user touches first.
| PWA · Android | PWA · iOS 16.4+ | Native · iOS | Native · Android | |
|---|---|---|---|---|
| Install affordance discoverable by AT | If the dev did it right | Add-to-Home-Screen menu — discoverable | App Store — fully accessible | Play Store — fully accessible |
| App name + description on launcher icon | Yes | Yes (name + apple-mobile-web-app-title) | Yes (UIKit Info.plist) | Yes (Android manifest) |
| Adaptive icons (themed / monochrome) | Yes (maskable) | No | Yes | Yes |
| App-switcher context announced | Yes | Partial | Yes (UIWindow title) | Yes |
| OS share sheet entry | Yes (share_target) | No | Yes (UIActivity) | Yes (Intent filter) |
| Long-press shortcuts | Yes (shortcuts) | No | Yes (UIApplicationShortcutItem) | Yes |
| Push-notification accessible content | Yes | Yes (since iOS 16.4) | Yes | Yes |
| Custom rotor / quick nav | N/A | N/A | Yes | Yes |
iOS 16.4 unlocked the install path, push notifications, and the badging API for PWAs, and iOS 17 closed the gap further on the basic launch surface. But file_handlers, share_target, shortcuts, and window_controls_overlay remain unsupported. For an AT user who relies on the OS share sheet to move content between apps, a PWA on iOS is still a meaningfully smaller surface than a PWA on Android or a native iOS app.
Conclusion: the 2026 playbook
Ship the install affordance as a real <button> with an accessible name. Wire a polite live region to the userChoice outcome. Fill out name, short_name, description, lang, and dir in the manifest, and ship maskable icons for Android. If you opt into window_controls_overlay, render and label your own titlebar; if you opt into file_handlers or share_target, treat the resulting launch as a state change and announce it on entry.
Restore focus to a labeled landmark every time the screen-reader user crosses the seam — first launch, app-switcher return, offline transition, share-target launch, reconnection. Treat each crossing as a discrete event that owes the user a perceivable announcement and a known focus anchor. None of this is hard; almost none of it is shipped consistently.
A PWA in 2026 can be very nearly indistinguishable from a native app for an assistive-tech user — on Android. On iOS it is closer than it was, and still has a real gap. The gap is closing roughly one manifest property per year. For procurement teams choosing between a PWA and a native app, the accessibility question is no longer “can a PWA be accessible?” — it can. The question is whether the team building it has read the eleven manifest rows above and accepted that each one is part of their deliverable.
”A PWA wrapper does not absolve a team of the platform-integration work. It adds eleven new accessibility surfaces and asks the team to handle each one on every platform it ships to.”