TL;DR
Accessibility is not a feature you add at the end. It’s an architectural decision that shapes component design, state management, routing, and testing from the first line of code.
Core principles:
The power of the Web is in its universality. Access by everyone regardless of disability is an essential aspect.
The Afterthought Problem
Most 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 for a simple reason: accessibility is not a layer you add on top, it is a foundation you build from.
The decisions you make on day one determine whether accessibility is achievable or impossible. Not difficult or easy. Achievable or impossible.
Think about that distinction. Some decisions close doors permanently. Others leave them open.
When you build without considering accessibility, you accumulate technical debt. Not the manageable kind that you can refactor away in a sprint, but the structural kind that requires rethinking entire systems. Components built without semantic meaning. State updates that never reach screen readers. Navigation flows that only work with a mouse. Forms that cannot be completed without sight.
Every day you wait makes the debt worse. Every component you add that lacks accessible patterns becomes another thing to fix. The codebase grows around inaccessible foundations, and fixing them means touching everything.
Architecture, Not Decoration
Accessibility is architectural because it affects every layer of your application. This isn’t abstract theory—it’s lived reality for anyone who has tried to retrofit accessibility into an application designed without it.
How Accessibility Shapes 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. URL changes that do not announce to screen readers create invisible navigation.
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.
When you build accessible applications, you're making fundamental choices about how your application understands and communicates its own structure. Accessibility forces you to articulate what your interface actually is, not just how it looks.
This is why accessibility is architectural. It cannot be retrofitted without touching every architectural decision you have made.
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. Buttons that trigger actions. This baseline functionality is inherently accessible because HTML has accessibility built in.
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 simultaneously:
- 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 navigation means your site works with broken mice or touch devices
- Focus management means your application works with various input methods
- ARIA announcements provide feedback even when visual updates fail
These are not separate concerns that happen to align. They are the same concern viewed from different angles. Both require treating HTML as your foundation rather than a rendering target for JavaScript.
See The Progressive Enhancement Mindset for a deeper understanding of how these approaches reinforce each other.
Semantic HTML as Bedrock
Every accessible application starts with semantic HTML. Not <div> elements with role attributes, but actual semantic elements that convey meaning.
This might sound like a simple technical choice, but it represents something deeper: a recognition that HTML was designed with meaning built in.
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.
When you choose the right element, you're documenting your intent in the structure itself. The code becomes self-describing.
These elements do more than render pixels. They 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 is 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.
Start with semantic HTML. Use ARIA only when HTML cannot express what you need.
Component Design Starts With Accessibility
When you design components, accessibility shapes fundamental decisions about interfaces and composition.
Consider a modal dialog. The accessible implementation requires many coordinated pieces. These are not optional features you add later. They define what a modal is. A modal without focus management is not a modal; it is 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 questions are not about styling, they are about component behavior.
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.
None of these patterns can be added after the component is built. They affect state management, keyboard event handling, DOM structure, and component lifecycle. They must be part of the initial design, or you end up rebuilding the component from scratch.
This is not about making simple things complicated. It is about recognizing that interactive widgets have well-defined behaviors, and accessible behavior is core behavior, not additional behavior.
State Management and Announcements
Your state management architecture determines whether users know what is happening in your application.
When state changes, visual users see the update. A message appears. A color changes. Content loads. But none of these visual cues reach screen reader users unless you explicitly communicate them.
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 cannot be an afterthought you add to every component individually. They need to be part of your state management layer.
When you dispatch an action that shows a notification, that action should trigger an announcement. When you transition to a loading state, that transition should announce. When you update data, that update should announce if it affects content the user is focused on.
This is why libraries like React, Vue, and Svelte added lifecycle hooks and effect systems. You need to coordinate DOM updates with side effects like announcements. But the framework cannot know what to announce or when. That is an architectural decision you make when designing your state layer.
Live regions are the mechanism. aria-live="polite" for non-urgent updates. aria-live="assertive" for critical information. aria-atomic to announce the entire region or just changes. aria-relevant to specify what types of changes matter. But these attributes only work if you pipe state changes through them consistently.
Building this coordination into your architecture means every developer on your team gets announcements right. Building it as an afterthought means every developer needs to remember to add announcements manually, and they 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 do not announce it. Scroll position might change or might not. Users are disoriented.
Accessible Routing Requirements
What You Must Do
- 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
Why This Matters
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 from day one means it works correctly from the start.
Testing From the Start
Accessibility testing is not something you do before launch. It is something you do during development, starting from the first component.
Accessibility is not a compliance checklist you run through before shipping. It is a definition of 'working' that includes everyone.
When you write a component, test it with keyboard navigation. Can you reach every interactive element? Can you trigger every action? Can you see focus indicators? If not, the component is broken, not “working but needs accessibility.”
When you add dynamic content, test it with a screen reader. Does content announce when it loads? Do errors announce? Do state changes communicate? If not, the feature is incomplete.
When you build forms, test them with various input methods. Keyboard, screen reader, voice control, switch control. Can you complete the form? Can you fix errors? Can you submit? If not, the form does not work.
Testing from the start catches problems when they are cheap to fix. One component with incorrect ARIA attributes takes five minutes to correct. Fifty components with incorrect patterns takes weeks.
Automated testing helps but cannot replace manual testing. Tools like axe-core, pa11y, and Lighthouse catch obvious issues. Missing alt text. Insufficient contrast. Invalid ARIA. But they cannot catch incorrect keyboard behavior, confusing focus management, or unhelpful announcements. Those require human testing.
Build manual accessibility testing into your development workflow. Use a screen reader. Use only keyboard. Try voice control. Test under various visual impairments with browser tools. Make this as routine as testing in different browsers.
The Real Cost of Ignoring Accessibility
The costs of ignoring accessibility are real, measurable, and increasing.
Legal costs are rising. The number of accessibility lawsuits filed in the U.S. increased from 2,314 in 2018 to over 4,500 in 2023. Defense costs start at $50,000 even when you settle quickly. Litigation can exceed $200,000.
Companies have paid millions in settlements. Domino’s Pizza, Netflix, Winn-Dixie, Beyoncé’s website, and hundreds of others faced lawsuits under the Americans with Disabilities Act. The courts consistently ruled that websites are places of public accommodation subject to accessibility requirements.
Beyond legal costs, you exclude paying customers. When your site is inaccessible, you turn away customers who want to buy from you. This is not a charitable concern, it is a business concern. You are leaving money on the table.
Organizations report retrofitting projects taking 6-12 months with multiple engineers dedicated full-time. You are not building features, you are fixing what should have been built correctly initially.
The retrofitting checklist:
- Auditing every component and page
- Redesigning component APIs to support accessibility
- Rewriting components that cannot 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 is also an ethical cost. When you build inaccessible software, you exclude people from participating in digital society. Banking, shopping, education, government services, entertainment—all increasingly online. Making these inaccessible creates real barriers for disabled people in their daily lives. This matters beyond legal and business concerns.
The Upside of Building It Right
The costs of ignoring accessibility are high, but the benefits of building it correctly are also significant.
The Benefits
Better Code
Accessible code is often better code. Semantic HTML is easier to maintain than <div> soup with role attributes. Keyboard navigation works for everyone, not just keyboard users. Focus management makes your UI more predictable.
Avoid Retrofitting Tax
Every feature ships accessible from day one. There is no cleanup phase. No compliance panic before launch. No expensive audits revealing fundamental architectural problems. 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 do not need to verify each component individually.
Reduced Legal Risk
You are not immune to lawsuits, but having demonstrable accessibility practices significantly reduces your exposure. Many suits target the worst offenders—sites that are obviously, egregiously inaccessible.
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
You build the web the way it is meant to be built. Accessible to everyone, regardless of ability. That is not just good ethics or good business. It is good engineering.
Building Accessibility Into Your Culture
Making accessibility foundational requires cultural change, not just technical change.
Developers
Developers need training. Not a single workshop they forget, but ongoing education:
- 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. Not as a separate accessible version, but as part of the primary design:
- 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. Not as technical debt or nice-to-have polish, but as core functionality:
- Accessibility work should be estimated in stories
- Accessibility bugs should be treated as any other bug—they prevent 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. But it is necessary for accessibility to be truly foundational.
When accessibility is one person’s responsibility, it becomes an afterthought. When it is everyone’s responsibility, it becomes part of how you build software.
The Path Forward
Accessibility as a foundation means treating it as architectural from day one. It shapes component design, state management, routing, and testing. It cannot be added at the end without significant rework.
Start with semantic HTML. Use the right elements for the job. Layer enhancements on top of solid structure. Test with keyboards and screen readers as you develop. Build announcements into state management. Integrate focus management into routing. Make accessibility part of your definition of working.
This approach costs less than retrofitting. It avoids legal risk. It expands your audience. It produces better software. Most importantly, it builds the web as an accessible platform for everyone.
That is not optional. That is foundational.
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, eliminates retrofitting, and reaches more users
Remember: accessibility is not a feature you add later. It is how you define “working” from the start.
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