TL;DR
Accessibility is an architectural decision that shapes component design, state management, routing, and testing from the first line of code, rather than a feature you add at the end.
Core principles:
The power of the Web is in its universality. Access by everyone regardless of disability is an essential aspect.
The Afterthought Problem
I’ve watched many development teams treat accessibility the same way they treat security audits or performance optimization: something to worry about later. Ship the feature first, make it accessible second. Get to MVP, then circle back for WCAG compliance.
This approach fails because accessibility depends on decisions made at the very beginning, and adding it later means going back and changing those decisions.
The decisions you make on day one can decide whether making your app accessible later is possible at all.
Some of those decisions are very hard to reverse later, and others leave your options open.
When you build without considering accessibility, you build up technical debt, and it’s usually the structural kind that means rethinking entire systems rather than the kind you can refactor away in a sprint: components built without semantic meaning, state updates that never reach screen readers, navigation flows that only work with a mouse, forms that can’t be completed without sight.
The debt grows with every component you add that lacks accessible patterns, because each one becomes another thing to fix. The rest of the codebase grows around those components, and fixing them later means touching everything.
Architecture, Not Decoration
Accessibility is architectural because it affects every layer of your application. You can see this every time someone tries to retrofit accessibility into an application designed without it.
Accessibility in Every Layer
Component Hierarchy
Your component hierarchy determines whether focus management works correctly. A modal that renders outside the component tree breaks keyboard navigation unless you explicitly manage focus. A dropdown menu needs ARIA attributes coordinated with JavaScript state.
State Management
Your state management determines whether assistive technologies understand your application. When content updates dynamically, screen readers need to know. When an error occurs, keyboard users need to receive focus. When a form validates, the validation state needs to be announced.
Routing
Your routing determines whether navigation works for everyone. Client-side routing that never updates focus leaves keyboard users lost in the page. When a URL change isn’t announced, screen reader users don’t know the page changed.
Data Fetching
Your data fetching affects whether loading states are accessible. When you fetch data, someone using a screen reader needs to know loading started, when it finished, and whether it failed. Spinners that are purely visual exclude blind users.
Building an accessible application means deciding how it describes its own structure to assistive technology. You have to spell out what each part of the interface is, as well as how it looks.
That’s why retrofitting accessibility means going back over every one of those decisions.
The Progressive Enhancement Connection
Progressive enhancement and accessibility share the same foundation: semantic HTML.
When you build with progressive enhancement, you start with HTML that works everywhere: forms that submit, links that navigate, and buttons that trigger actions. This baseline is accessible from the start because browsers already know how to expose those elements to assistive technology.
Two Sides of the Same Coin
When You Abandon Semantic HTML
When you abandon HTML in favor of <div> soup with JavaScript event handlers, you lose both progressive enhancement and accessibility at the same time:
- Click handlers don’t work without JavaScript
- Keyboard navigation doesn’t exist
- Screen reader users receive no semantic information
- Only works in JavaScript-enabled, mouse-driven browsers
When You Build Accessible
When you build accessible applications, you get progressive enhancement benefits for free:
- Semantic HTML works without JavaScript
- Keyboard support means your site works with switch devices and with keyboards attached to tablets and phones
- Focus management means your application works with various input methods
- Live region announcements tell screen reader users about changes they can’t see
Progressive enhancement and accessibility are the same concern seen from two directions. Both treat HTML as your foundation rather than a rendering target for JavaScript.
See The Progressive Enhancement Mindset for more on how the two approaches support each other.
Semantic HTML as Bedrock
Every accessible application starts with semantic HTML: elements that have meaning of their own, rather than <div> elements with role attributes added.
That can look like a minor technical choice, but HTML was designed with meaning built into its elements.
Use the right element: <button> for actions, not <div onClick>. <a> for navigation, not <span> with routing. <main>, <nav>, <aside>, <article>, <section> to structure content. <form> to collect input. <label> to describe fields. <table> for tabular data, not layout.
Choosing the right element documents your intent in the markup itself, so the code describes what it does.
These elements also communicate structure and intent to assistive technologies. A screen reader announces “button” when encountering a <button>, but “clickable” or nothing at all when encountering a <div> with an onclick handler.
Semantic HTML vs ARIA
Choose the Right Element
When you choose the right element, you get accessibility for free:
- Focus management works
- Keyboard interaction works
- Screen reader announcements work
- ARIA attributes are rarely needed because the semantics are already present
Wrong Element + ARIA = Playing Catch-Up
When you choose the wrong element and try to fix it with ARIA:
- You need to add
role="button"andtabindex="0" - You need
onKeyDownhandlers for Space and Enter keys - You need to add
aria-labelbecause there’s no semantic content - You need to manage focus explicitly
The first rule of ARIA is to not use ARIA if semantic HTML can accomplish the same thing. Every ARIA attribute you add is a maintenance burden.
Component Design Starts With Accessibility
When you design components, accessibility shapes decisions about each component’s API and how components fit together.
Take a modal dialog. An accessible modal needs the coordinated pieces listed alongside, and they define what a modal is rather than being optional features you add later. Without focus management, a modal is just a div that appears on top of content.
Your component API needs to support these requirements. Where does focus return when the modal closes? What element should receive initial focus? Is the modal dismissible? These are questions about how the component behaves, not how it looks.
The same applies to every interactive component. A tabs component needs roving tabindex, arrow key navigation, Home and End key support, aria-selected, and proper label associations. A combobox needs aria-expanded, aria-autocomplete, aria-activedescendant, and specific keyboard interactions.
These patterns are very hard to add after the component is built, because they affect state management, keyboard event handling, DOM structure, and component lifecycle. They have to be part of the initial design, or you end up rebuilding the component from scratch.
Interactive widgets have well-defined behaviors, and the accessible behavior is part of each widget’s core behavior rather than something extra on top.
State Management and Announcements
Your state management architecture determines whether users know what’s happening in your application.
When state changes, visual users see the update: a message appears, a color changes, content loads. Screen reader users only find out about these changes if you communicate them explicitly.
This requires coordinating state changes with announcements. When a form submission succeeds, you need to announce success. When data loads, you need to announce completion. When validation fails, you need to announce errors and move focus to the first invalid field.
These announcements belong in your state management layer, rather than being added to each component one at a time.
When you dispatch an action that shows a notification, that action should trigger an announcement too. The same goes for moving into a loading state, and for updating data that affects content the user is focused on.
Frameworks like React, Vue, and Svelte give you lifecycle hooks and effect systems for coordinating DOM updates with side effects like announcements. But the framework can’t know what to announce or when. You decide that when you design your state layer.
The announcements themselves go through live regions: aria-live="polite" for non-urgent updates, aria-live="assertive" for critical information, aria-atomic to choose between announcing the entire region or just the changes, and aria-relevant to specify which types of changes get announced. These attributes only work if you send state changes through them consistently.
If this coordination is built into your architecture, every developer on your team gets announcements right without thinking about it. If it’s added later, every developer has to remember to add announcements by hand, and some of them will forget.
Routing and Focus Management
Client-side routing breaks accessibility by default.
When you navigate with traditional links, the browser handles everything: it requests the page, renders content, resets scroll position, and moves focus to the top of the page. Users know navigation occurred because the page reloaded.
When you intercept clicks and render new content with JavaScript, none of this happens automatically. The URL changes but focus stays on the link the user clicked. The page content updates but screen readers don’t announce it. Scroll position may or may not change, and users are left disoriented.
Accessible Routing Requirements
Required Steps
- Move focus to the new content after navigation completes
- Announce the navigation to screen readers
- Update page titles so browser history makes sense
- Handle loading states accessibly
- Handle interrupted navigation when a new route loads before the previous one finishes
Effect on Your Architecture
These requirements shape your routing architecture. You need lifecycle hooks that run after navigation. You need a consistent target for focus management. You need a way to announce route changes.
If you build client-side routing without considering accessibility, you create an application that only works for sighted mouse users. Retrofitting focus management means revisiting every route, every route guard, every navigation trigger.
Building it in from day one avoids that rework.
Testing From the Start
Accessibility testing belongs in development, starting from the first component, rather than in a pass just before launch.
Accessibility belongs in your definition of 'working', rather than on a compliance checklist you run through before shipping.
When you write a component, the first check is keyboard navigation: can you reach every interactive element, trigger every action, and see the focus indicators? If not, the component is broken, not “working but needs accessibility.”
When you add dynamic content, a screen reader tells you whether the content is announced when it loads, whether errors are announced, and whether state changes come through. If they don’t, the feature is incomplete.
Forms need testing with several input methods: keyboard, screen reader, voice control, switch control. If you can’t complete the form, fix errors, and submit with each of them, the form doesn’t work.
Testing from the start catches problems while they’re cheap to fix. One component with incorrect ARIA attributes takes five minutes to correct, and fifty components with incorrect patterns take weeks.
Automated testing helps but can’t replace manual testing. Tools like axe-core, pa11y, and Lighthouse catch obvious issues: missing alt text, insufficient contrast, invalid ARIA. But they can’t catch incorrect keyboard behavior, confusing focus management, or unhelpful announcements. Those require human testing.
Manual accessibility testing works best as part of your normal development workflow: using a screen reader, using only the keyboard, trying voice control, and checking the page under simulated visual impairments with browser tools. It can be as routine as testing in different browsers.
The Cost of Ignoring Accessibility
Ignoring accessibility has legal and business costs, and the legal ones are rising. UsableNet counted 2,314 digital accessibility lawsuits filed in the U.S. in 2018, and more than 5,000 in 2025 across federal and state courts. Even a suit that settles quickly comes with legal fees on top of the cost of fixing the site.
Settlements can be large: Target paid $6 million in damages to settle a class action over its website in 2008. Domino’s Pizza, Netflix, Winn-Dixie, Beyoncé’s website, and hundreds of others faced lawsuits under the Americans with Disabilities Act. Several courts have ruled that websites can count as places of public accommodation subject to accessibility requirements, though not every court has agreed.
An inaccessible site also turns away customers who want to buy from you, which makes accessibility a business problem as well as an ethical one. You’re leaving money on the table.
Retrofitting a large application can tie up several engineers for months. That's time spent fixing existing features instead of building new ones.
The retrofitting checklist:
- Auditing every component and page
- Redesigning component APIs to support accessibility
- Rewriting components that can’t be made accessible
- Updating state management to handle announcements
- Fixing routing and focus management globally
- Testing everything again across devices and assistive technologies
- Training your entire team on accessible patterns
There’s also an ethical cost. Banking, shopping, education, government services, and entertainment are increasingly online, so inaccessible software creates real barriers for disabled people in their daily lives, whatever the legal or business picture.
The Upside of Building It Right
Building accessibility in from the start also has benefits of its own.
The Benefits
Better Code
Accessible code is often better code. Semantic HTML is easier to maintain than <div> soup with role attributes. Keyboard navigation helps power users as well as the people who rely on it. Focus management makes your UI more predictable.
No Retrofitting Project
Every feature ships accessible from day one. There’s no separate cleanup phase before launch, and audits are less likely to find problems built into the architecture. You build it right the first time.
Easier Testing
When components follow consistent accessible patterns, you know what to test. When state management handles announcements architecturally, you don’t need to check the announcement logic in each component separately.
Reduced Legal Risk
You’re not immune to lawsuits, but having demonstrable accessibility practices reduces your exposure and puts you in a much better position if a complaint does arrive.
Expanded Market
Accessible sites reach more users, including elderly users with declining vision or motor control, users with temporary disabilities like broken arms, and users in situational limitations like bright sunlight or noisy environments.
Good Engineering
Building sites that everyone can use, regardless of ability, is good ethics and good business, and it’s also good engineering.
Building Accessibility Into Your Culture
Making accessibility foundational takes cultural change as well as technical change.
Developers
Developers need ongoing training rather than a single workshop they forget, backed up by how the team works:
- Accessible patterns should be in your component library
- Code reviews should check accessibility
- Pull request templates should include accessibility testing steps
- Accessibility should be a normal part of definition of done
Designers
Designers need to design for accessibility as part of the primary design, rather than as a separate accessible version:
- Color contrast should be verified in design tools
- Focus states should be designed
- Keyboard interaction should be specified
- Screen reader announcements should be documented
Product Managers
Product managers need to prioritize accessibility as core functionality, rather than as technical debt or nice-to-have polish:
- Accessibility work should be estimated in stories
- Accessibility bugs should be treated like any other bug, because they stop the feature from working correctly
- Shipping inaccessible features should be as unacceptable as shipping broken features
The Organization
This is organizational change, and it takes time. As long as accessibility is one person’s job, it tends to stay an afterthought, and it only becomes part of how you build software once everyone shares it.
The Path Forward
Accessibility has to be part of the architecture from day one. It shapes component design, state management, routing, and testing, and adding it at the end takes significant rework.
In practice, that means starting with semantic HTML and the right elements for the job, layering enhancements on top of that structure, testing with keyboards and screen readers as you develop, building announcements into state management and focus management into routing, and making accessibility part of what “working” means.
This approach takes less work than retrofitting, lowers your legal risk, reaches more people, and produces better software. Most of all, it keeps the web usable by everyone.
Summary
- Accessibility is architectural, not cosmetic. It shapes component design, state management, and routing from day one
- Start with semantic HTML and progressive enhancement to get accessibility built-in
- Test with keyboard and screen readers during development, not before launch
- Build announcements into state management and focus management into routing
- Ignoring accessibility creates legal, financial, and ethical costs that compound over time
- Making accessibility foundational creates better code, avoids a retrofitting project later, and reaches more users
Accessibility belongs in how you define “working” from the start, rather than being a feature you add later.
Related Content:
- Foundations: The Progressive Enhancement Mindset, Separation of Concerns, Component-Driven Architecture
- Principles: Baseline-First Thinking, Defense in Depth
- Patterns: Form Enhancement Pattern, Focus Management Pattern, Announcement Pattern, Keyboard Navigation Pattern
External Resources:
- Web Content Accessibility Guidelines (WCAG) - Official accessibility standards
- ARIA Authoring Practices Guide - Patterns for accessible rich internet applications
- A11y Project - Community-driven accessibility resource
- WebAIM - Web accessibility training and resources
- Inclusive Components - Accessible component patterns by Heydon Pickering
- Deque University - Comprehensive accessibility training materials
- MDN: Accessibility - Mozilla’s accessibility documentation