Chapter 29: Accessibility Is the Platform Contract
Accessibility is often treated as a checklist.
Add labels. Add roles. Check contrast. Fix focus. Run an automated audit. Move on. The work is something the team does at the end of a feature, or the week before launch, or after a complaint, or never.
That posture is wrong, and the chapter has to name the wrongness directly before the architectural argument can land.
Accessibility isn’t a layer over an application. It’s part of the contract between HTML, CSS, JavaScript, the browser, assistive technologies, and the people who use the application. When we build with native semantics, the browser upholds most of the contract for us. When we replace native behavior with custom code, we inherit the responsibility — and most of the field’s custom code routinely fails to honor what the platform was already providing.
This chapter argues that accessibility is architecture, not aftercare. It’s a structural commitment the platform makes, and applications either honor that commitment or break it. The web’s history includes a substantial body of work by a small community of people who’ve been making this argument for thirty years. The chapter gives that community its due.
What Tim Berners-Lee Said
Section titled “What Tim Berners-Lee Said”Tim Berners-Lee, in 1997, wrote:
The power of the web is in its universality. Access by everyone regardless of disability is an essential aspect.
The quote is one of the most-cited in accessibility writing. It’s worth quoting because it represents the platform’s founding intent. The web wasn’t designed as a sighted, mouse-using, English-speaking, full-cognitive-capability experience that accessibility teams later had to retrofit. It was designed, from the start, as a medium intended to work across the full range of human capability.
The same year, 1997, Berners-Lee and Judy Brewer launched the W3C’s Web Accessibility Initiative (WAI). The WAI’s charter was to make sure the web’s universality wasn’t a slogan but a working design constraint. Twenty-eight years later, the WAI is still operating, with Brewer still involved, and the institutional work has produced specifications, conformance criteria, and tooling that the rest of this chapter will reference.
The accessibility commitment is older than most of the frameworks this book has discussed. It predates jQuery by almost a decade. It predates React by sixteen years. The architectural choices that respect it are not new constraints the field is being asked to adopt; they’re the platform’s original design principles that frontend has, for long stretches of its history, been working around.
WCAG and Its Evolution
Section titled “WCAG and Its Evolution”The most-cited accessibility standard is the Web Content Accessibility Guidelines — WCAG.
WCAG 1.0 shipped in 1999, organized around guidelines for ensuring web content was perceivable, operable, and understandable. The document was prescriptive about specific techniques (use alt attributes, use heading hierarchy, ensure keyboard access) and structured around HTML 4.0’s vocabulary.
WCAG 2.0 (2008) was a major reorganization. The guidelines were restructured around four principles — Perceivable, Operable, Understandable, Robust — with success criteria at three levels (A, AA, AAA). The technique-agnostic framing made WCAG applicable to technologies that didn’t exist when it was written (mobile apps, single-page applications, web components). WCAG 2.0 became the working standard for legal accessibility requirements in the U.S., the E.U., and many other jurisdictions.
WCAG 2.1 (2018) added criteria for mobile, low vision, and cognitive disabilities — gestures, reflow, orientation independence, target sizes, identification-of-purpose.
WCAG 2.2 (2023) added more criteria for cognitive accessibility, focus appearance, dragging-movement alternatives, and accessible authentication.
WCAG 3.0 is in development. The 3.0 work is moving toward an outcome-based scoring model and a broader scope (mobile apps, XR, AI-generated content). It’s not yet ratified.
The practical baseline for most teams in 2025 is WCAG 2.1 AA. This is what most legal accessibility requirements specify. The European Accessibility Act, with enforcement deadlines through 2025–2026, requires WCAG 2.1 AA for many categories of digital products sold or operated in the EU. The U.S. has parallel requirements through ADA case law (the Robles v. Domino’s Supreme Court case in 2019 confirmed that the Americans with Disabilities Act applies to commercial websites) and Section 508 (for federal procurement).
The legal frame is real, and the lawsuits are real. Domino’s settled. Beyoncé.com was sued. Hundreds of major retailers face accessibility complaints annually. The legal cost of inaccessible applications has been rising and will continue to. The argument for accessibility includes a moral dimension (people with disabilities deserve access to digital services) and an operational dimension (building accessible applications avoids legal exposure). For most teams, both arguments lead to the same conclusion.
Who This Is For
Section titled “Who This Is For”The scale matters. The CDC estimates that roughly one in four adults in the United States has some form of disability. The WHO estimates around 1.3 billion people globally live with significant disability. The numbers include people with visual impairments (low vision, color blindness, blindness), motor impairments (limited mobility, tremors, paralysis), hearing impairments (hard of hearing, deaf), cognitive differences (dyslexia, autism, ADHD, age-related cognitive decline), and many other categories.
Most of these users aren’t using assistive technology in the screen reader sense the field tends to picture. They’re zooming the page. They’re using keyboard navigation because a mouse is uncomfortable. They’re relying on captions because the audio is hard to hear. They’re using the browser’s reader mode to strip out distracting elements. They’re using voice control to dictate. They’re using high-contrast mode because the design’s gray-on-gray is invisible to them. They’re using the browser’s autofill because typing is slow and tiring.
The architecture that respects accessibility isn’t designed for a small population of screen-reader users. It’s designed for the way real people actually use the web — across vision, hearing, motor, cognitive, and situational variations that affect a much larger share of users than the typical user the design specs were drawn for.
Native Semantics Are Infrastructure
Section titled “Native Semantics Are Infrastructure”The architectural argument the chapter has to make is the one Chapter 20 introduced.
A native <button> has a role (announced as button). It has keyboard activation (Enter and Space both fire its click event). It can be focused (Tab moves to it; the focus ring shows where focus is). It can be disabled (disabled attribute; the platform handles the visual state, the keyboard interaction, the form-submission exclusion). It has an accessible name (its text content, or its aria-label, computed by the browser’s accessibility name algorithm). It participates in forms (a button inside a form submits the form). It behaves consistently across input methods (mouse, keyboard, touch, voice control, switch control).
A <div> with a click handler has none of that. A screen reader user encounters the <div> and hears nothing useful about it. A keyboard user can’t reach the <div> at all unless the developer adds tabindex. A voice-control user can’t say click the Save button because nothing in the platform identifies the <div> as a button. The platform has been bypassed; the application’s custom code has to recreate every behavior the platform was providing.
This is the engineering argument. The platform’s native elements are infrastructure, in the same sense that an operating system’s standard widget toolkit is infrastructure. Replacing the infrastructure with custom code is a substantial commitment, and most teams that replace native elements do so without making the commitment explicitly. The result is the long tail of inaccessible custom controls that fill the web.
The Accessibility Tree, Revisited
Section titled “The Accessibility Tree, Revisited”Chapter 20 introduced the accessibility tree. The detail worth adding here is that the tree is not the same as the DOM tree, and the difference matters.
The DOM tree contains everything in the document. The accessibility tree contains only the elements that have meaning to assistive technologies, with their roles, names, and states.
When the browser computes the accessibility tree, it makes several decisions. Elements with no semantic role and no content are typically pruned. display: none and visibility: hidden elements are excluded entirely. aria-hidden="true" elements and their descendants are excluded from the accessibility tree but still appear in the DOM. Elements with the role presentation or none are excluded from the accessibility tree while their children remain.
This is one of the most-misunderstood corners of accessibility. The application can have a perfectly structured DOM that produces a poorly structured accessibility tree, and vice versa. The tools that inspect accessibility (Chrome DevTools’ Accessibility panel, Firefox’s Accessibility Inspector, the Mac’s VoiceOver utility) show the accessibility tree, not the DOM. Audit the accessibility tree, not the DOM, when checking for accessibility issues.
The accessibility tree is also what most automated tools — axe-core (by Deque Systems), Pa11y, Lighthouse, IBM’s Equal Access — analyze. The tools walk the accessibility tree, check it against rules derived from WCAG, and report issues. They’re useful but limited. Roughly 30–50% of WCAG issues are caught by automated tools, depending on the study; the remaining 50–70% require human review, particularly for content quality, keyboard interaction flow, and screen-reader announcement appropriateness.
ARIA Done Right
Section titled “ARIA Done Right”The first rule of ARIA (Chapter 20 introduced it) is don’t use ARIA when you can use HTML. The W3C’s ARIA Authoring Practices Guide opens with this point.
The reason is that ARIA only modifies the accessibility tree. It doesn’t add behavior. role="button" on a <div> makes the accessibility tree announce button, but the <div> still doesn’t respond to Enter or Space. The application has to add the keyboard handler. The focus ring. The aria-disabled semantics. The form-submission behavior. The platform won’t help.
ARIA is essential for things the platform doesn’t have native elements for — role="tablist" and its children for tabbed interfaces, aria-live for dynamic content announcements, aria-current="page" for active navigation items, aria-controls and aria-expanded for collapsible regions, and a handful of other patterns. When you need ARIA, use it carefully. The Authoring Practices Guide has worked patterns for most common cases; deviating from them is hazardous.
The pattern is: try HTML first. If HTML works, use HTML. If a native element does most of what you need but lacks one or two semantics, add ARIA to fill the gaps (aria-label, aria-describedby, aria-current, the state attributes). If the pattern has no native element at all (a tablist, a tree view, a complex menu), use ARIA carefully following established patterns.
Focus Is Application Flow
Section titled “Focus Is Application Flow”Focus management is one of the areas where applications most often fail.
A keyboard user’s focus is their cursor — it’s where their next action will land. Moving focus is the equivalent of moving the user’s mouse. Losing focus is the equivalent of disappearing the user’s mouse. An application that breaks focus is, for keyboard and screen-reader users, broken in the way an application that randomly hides the cursor would be broken for mouse users.
The common failures are predictable. A modal opens and focus stays behind the modal (the user can’t reach the modal’s content with Tab). A modal closes and focus disappears (the user has to scroll back to where they were). A re-render replaces the focused element with a new one and focus jumps to the document body. A custom select opens and focus stays on the trigger (the user can’t reach the options with arrow keys). A page-level navigation happens without tabindex management and focus lands on <body> (the user has to Tab through every header element again).
The platform’s native elements handle most of this automatically. <dialog> (since 2022) manages focus trap, focus restoration, and Escape-to-close. <details> manages focus on the disclosure summary. <button> and form controls participate in the document’s tab order without configuration. The platform’s customizable <select> (emerging in 2024–2025) inherits the platform’s select-control focus behavior.
When the application uses non-native elements, it has to manage focus explicitly. Trap focus inside the open modal. Restore focus to the element that triggered the modal when it closes. Move focus to the new content when a route changes. Don’t replace focused elements without restoring focus. Each of these is a discipline the application has to maintain.
For Kitsune’s component library, focus management is part of every component’s published contract. The <kit-dialog> documents what it does to focus. The <kit-menu> documents its keyboard navigation. The components that wrap native elements inherit the platform’s behavior; the components that have to be custom take on the responsibility explicitly.
Shadow DOM and Accessibility
Section titled “Shadow DOM and Accessibility”Shadow DOM (touched on in Chapters 21 and 22) has accessibility implications.
When an element renders into a shadow root, the shadow tree is part of the document’s accessibility tree but the encapsulation boundary affects how some accessibility features work. aria-labelledby, which references an element by ID, can’t reach across shadow boundaries by default. Form-control labels that should be associated with custom elements need to be handled through ElementInternals (Chapter 24’s formAssociated mechanism).
The platform has been steadily improving shadow-DOM accessibility integration. The ariaLabel, ariaDescribedBy, and similar IDL properties on ElementInternals (added in 2023–2024) let custom elements declare their accessibility properties programmatically, without needing the DOM-attribute reference to work across the shadow boundary. The cross-root ARIA reference proposal is working its way through the standards process.
For Kitsune’s component library, the shadow-DOM accessibility story is part of the framework’s responsibility. Components encapsulate their internals, expose accessibility through ElementInternals and slotted content, and document what’s required for proper accessibility integration when consumed by an application.
Motion, Contrast, and Preference
Section titled “Motion, Contrast, and Preference”Accessibility isn’t only screen-reader support.
The prefers-reduced-motion media query (Chapter 28 introduced) gives users with vestibular issues a way to opt out of motion they find disorienting. Applications should honor it.
The prefers-color-scheme media query lets users with light sensitivity or other vision differences set a system-wide preference for light or dark interfaces. Applications should respect it for default theme choice.
The prefers-contrast media query (more recent) lets users request higher-contrast interfaces. Applications can adjust their color palettes accordingly.
The forced-colors media query (and the related forced-color-adjust CSS property) handles the Windows High Contrast Mode. When a user has high-contrast mode enabled, the operating system overrides colors to a user-chosen palette. Applications need to ensure their interfaces still work — the forced-colors query lets the CSS adjust for the override.
Zoom matters. WCAG requires that content remain usable at 200% zoom. Many designs break — text gets clipped, layouts overflow, controls become unreachable. Building responsive layouts that work at zoom levels up to 400% is an underrated accessibility skill.
Captions, transcripts, and alternative text matter. Any audio or video content needs captions for users who are deaf or hard of hearing, and transcripts for users who can’t watch the video. Images that convey meaningful content need alt attributes that describe the content. Decorative images need empty alt="" to indicate they should be skipped.
Cognitive accessibility matters. Plain language, clear structure, predictable navigation, sufficient time for tasks (or the ability to extend timeouts), error prevention, and confirmation for irreversible actions all help users with cognitive disabilities — and frankly, all users.
The pattern: the platform provides primitives for accessibility; the application has to use them. The primitives include media queries, ARIA attributes, native semantics, focus management, and the constraint-validation system. The application is responsible for putting them together in ways that respect the full range of user capability.
Where Frameworks Break the Platform’s Promises
Section titled “Where Frameworks Break the Platform’s Promises”The chapter has to name a pattern directly, even though it’s uncomfortable.
Most modern frontend frameworks routinely produce inaccessible applications. The reasons are structural. Components abstract over DOM details, so developers stop thinking about which native elements they’re using. State management abstracts over focus, so focus transitions get lost during re-renders. Routing abstracts over navigation, so screen-reader announcements get missed. CSS-in-JS abstracts over global stylesheets, so user-preference media queries get applied inconsistently. Every layer of abstraction is an opportunity to break a contract the platform was upholding.
The frameworks aren’t malicious. They’re focused on developer experience, performance, and the categories of complexity their teams have been most interested in solving. Accessibility hasn’t been the primary axis of attention for most framework design. The result is that making a framework application accessible is harder than making a server-rendered application accessible, in many specific ways.
This isn’t an argument that frameworks are bad. It’s an argument that frameworks have costs, and that the costs include a maintenance burden around accessibility that the platform-only version of the same application wouldn’t have. Teams that take accessibility seriously inside React, Vue, or Angular do real work. Teams that don’t take it seriously produce real harm.
The platform-first argument the book builds includes accessibility as a load-bearing reason. Code written against the platform inherits the platform’s accessibility contract. The native <form> element is accessible by default. The native <dialog> element is accessible by default. The native <button> element is accessible by default. The contract is upheld unless the application breaks it. The application has to do less work to be accessible because the platform was doing the work all along.
The People Doing This Work
Section titled “The People Doing This Work”The chapter has to give credit, because the work has been done by people, and most of them have done it without much acknowledgment.
Judy Brewer directed the WAI from its founding in 1997 through 2022, when she became the U.S. White House’s Assistant Director for Accessibility Policy. Brewer’s work shaped the WCAG specifications, the accessibility standards that most national regulations now reference, and the broader institutional commitment of the W3C to accessibility as a first-class concern.
Léonie Watson is a British accessibility consultant, a screen-reader user, and one of the most influential voices in modern accessibility advocacy. Watson has been a member of the W3C Advisory Board, co-chair of the Web Platform Working Group, and runs TetraLogical, a consultancy. Her writing and talks have been a primary source of accessibility education for working developers for over a decade.
Marcy Sutton has worked at Gatsby, Deque (the company behind axe-core), and as an independent consultant. Her conference talks — particularly on single-page application accessibility, ARIA patterns, and the integration of accessibility into modern frontend workflows — have shaped how a generation of frontend developers think about the work. Her writing on the accessibility implications of client-side routing is some of the clearest in the field.
Heydon Pickering’s book Inclusive Components (2018, published as part of Smashing Magazine’s catalog) is one of the most useful technical references in the field. The book walks through how to build common interactive components accessibly, with the kind of careful attention to keyboard interaction, focus management, and ARIA detail that most documentation skips.
Hidde de Vries is a Dutch developer and accessibility advocate who’s been a primary participant in the Open UI working group (which is working to make customizable native form controls possible). De Vries’s writing is widely read and pragmatically focused on the work developers actually have to do.
Adrian Roselli, Sarah Higley, Eric Bailey, Scott O’Hara, James Craig (Apple’s WebKit accessibility team), Aaron Leventhal (Mozilla’s accessibility work, then Google), the entire Deque team behind axe-core, and many more.
The maintainers of NVDA — Michael Curran and James Teh, the founders of NV Access, the small Australian non-profit that has been producing the free, open-source NVDA screen reader since 2006 — deserve specific mention. NVDA is the most widely-used screen reader after JAWS, and it costs nothing, which means it’s the only option for many users in lower-income contexts. The fact that the second-largest screen reader on the planet is maintained by a tiny non-profit is the kind of fact this book wants you to know.
The work these people have done is mostly thankless. The legal and ethical case for accessibility is overwhelming; the technical case is well-documented; the field still routinely produces inaccessible applications. The advocates’ patience is what’s kept the conversation going.
What Modern Frontend Should Do
Section titled “What Modern Frontend Should Do”For application architecture, the principles fall out of the chapter’s argument.
Start from semantic HTML. Use the native elements. Use the native controls. Use real <form>, <button>, <input>, <dialog>. The platform was already doing the work; let it.
Manage focus explicitly when you must. When the application introduces patterns the platform doesn’t directly support, focus management becomes the application’s responsibility. Document what each interactive component does to focus.
Use ARIA carefully. The first rule of ARIA is don’t use ARIA. The second rule is when you do, follow the W3C’s Authoring Practices Guide patterns.
Honor user preferences. prefers-reduced-motion, prefers-color-scheme, prefers-contrast, forced-colors. The platform exposes the preferences; respect them.
Test with assistive technology. Automated tools catch some issues. Manual testing with VoiceOver (built into Mac), NVDA (free, Windows), Narrator (built into Windows), or TalkBack (Android) catches the issues automated tools miss. The cost of installing and learning a screen reader is one afternoon.
Treat accessibility as architecture. Bake it into component design, into review checklists, into testing infrastructure, into the design system, into the team’s vocabulary. The architectural lift is real and the payoff is durable.
The platform’s accessibility contract is one of its most valuable affordances. Applications that respect the contract get most of the way to accessibility for free. Applications that bypass the contract have to recreate it, and most don’t recreate it well. The architectural argument the book builds includes accessibility as a structural reason to take the platform seriously.
What Comes Next
Section titled “What Comes Next”The next chapter takes a parallel structural commitment seriously — internationalization. The Intl API and the platform’s locale-aware capabilities are, like accessibility, an undervalued substrate that frameworks routinely break. The chapter argues that internationalization, like accessibility, is part of the platform’s contract — and that the platform has been ahead of where most application code is for years.
Exercise: Audit Two Dialogs
Section titled “Exercise: Audit Two Dialogs”Build or find two dialogs in an application you can modify:
- A
<div>-based modal — one that exists in your codebase already, or that you build to look indistinguishable from the second. - A native
<dialog>element usingshowModal().
Test both with the following procedure:
- Open with the keyboard (Tab to a button, press Enter to trigger). Does the dialog open?
- Where does focus move when the dialog opens? (For native
<dialog>, focus moves to the first focusable element inside. For most<div>modals, focus stays where it was unless the application moved it.) - Press Tab repeatedly inside the dialog. Does focus stay inside? (Native
<dialog>traps focus. Most<div>modals don’t, unless the application implements the trap.) - Press Escape. Does the dialog close? (Native
<dialog>closes on Escape. Most<div>modals don’t, unless the application implements the handler.) - When the dialog closes, where does focus go? (Native
<dialog>returns focus to the trigger. Most<div>modals leave focus on<body>or somewhere arbitrary.) - Open VoiceOver (Cmd-F5 on macOS) or NVDA (free download on Windows) and navigate the dialog. What does the screen reader announce?
- Is the dialog visually labelled? Is the label associated with the dialog via the accessibility tree?
- Try to click outside the dialog. Does the background content respond? Should it?
Reflect on:
- What did native
<dialog>provide for free? - What did the custom dialog need to rebuild?
- What did ARIA help with? What did it not solve?
- What behavior still required JavaScript even with native
<dialog>? - Which approach would you want shipping in a component library you’d be responsible for maintaining?
The goal is to feel that accessibility is a structural property of the architecture. The native dialog inherits the platform’s contract. The custom dialog has to recreate the contract in application code, line by line. The choice between the two has accessibility consequences that show up immediately and compound over years of maintenance.