Practice of designing and developing digital products usable by all people, including those with visual, auditory, motor, or cognitive disabilities.
Web accessibility (a11y) is the practice of making digital products usable by all people, regardless of their abilities. It's not an optional feature — it's a fundamental quality requirement and, in many jurisdictions, a legal one.
Approximately 16% of the world's population lives with some form of disability (WHO). Designing without considering accessibility actively excludes one in six people.
The Web Content Accessibility Guidelines (WCAG) are the international standard published by the W3C. Version 2.2, published in October 2023, adds 9 new success criteria over version 2.1, focused on cognitive accessibility, mobile usability, and authentication.
Three conformance levels:
| Criterion | Level | What it addresses |
|---|---|---|
| Focus Not Obscured (Minimum) | AA | Focused element cannot be completely hidden by other elements |
| Focus Not Obscured (Enhanced) | AAA | Focused element must be fully visible |
| Focus Appearance | AAA | Focus indicator with minimum area and contrast |
| Dragging Movements | AA | All drag functionality must have a non-dragging alternative |
| Target Size (Minimum) | AA | Touch targets at least 24x24 CSS pixels |
| Consistent Help | A | Help mechanisms in the same relative position across pages |
| Redundant Entry | A | Don't ask users to re-enter previously provided information |
| Accessible Authentication (Minimum) | AA | No cognitive function tests (e.g., transcribing CAPTCHAs) for authentication |
| Accessible Authentication (Enhanced) | AAA | No cognitive tests of any kind in the authentication flow |
Most regulations (ADA in the US, EN 301 549 in Europe, European Accessibility Act effective June 2025) require level AA as a minimum.
The four principles that organize all WCAG criteria:
Semantic HTML is always the first choice. ARIA (Accessible Rich Internet Applications) is used when native HTML cannot express a component's role or state.
<button> instead of <div role="button">role="heading" on a <button>role="presentation" or aria-hidden="true" on focusable elementsfunction Tabs({ tabs, activeTab, onChange }: TabsProps) {
return (
<div>
<div role="tablist" aria-label="Sections">
{tabs.map((tab, i) => (
<button
key={tab.id}
role="tab"
id={`tab-${tab.id}`}
aria-selected={activeTab === tab.id}
aria-controls={`panel-${tab.id}`}
tabIndex={activeTab === tab.id ? 0 : -1}
onClick={() => onChange(tab.id)}
onKeyDown={(e) => {
if (e.key === 'ArrowRight') onChange(tabs[(i + 1) % tabs.length].id);
if (e.key === 'ArrowLeft') onChange(tabs[(i - 1 + tabs.length) % tabs.length].id);
}}
>
{tab.label}
</button>
))}
</div>
{tabs.map((tab) => (
<div
key={tab.id}
role="tabpanel"
id={`panel-${tab.id}`}
aria-labelledby={`tab-${tab.id}`}
hidden={activeTab !== tab.id}
>
{tab.content}
</div>
))}
</div>
);
}Key points: role="tablist" groups the tabs, aria-selected indicates the active one, aria-controls connects tab to panel, and arrow keys enable keyboard navigation without Tab.
Automated tools detect between 30% and 40% of accessibility issues — those verifiable by code analysis (contrast, missing alt text, invalid ARIA roles). The remaining 60-70% requires human judgment: is the alt text meaningful? Does the reading order make sense? Is keyboard navigation logical?
| Aspect | Automated | Manual |
|---|---|---|
| WCAG coverage | 30-40% of criteria | 100% of criteria |
| Speed | Seconds | Hours |
| Consistency | Deterministic | Depends on evaluator |
| Detects | Contrast, missing alt, invalid ARIA, HTML structure | Reading order, alt text quality, keyboard flows, comprehensibility |
| Tools | axe-core, Lighthouse, eslint-plugin-jsx-a11y | Screen readers (NVDA, VoiceOver), keyboard navigation, expert review |
| When | On every commit (CI) | Before releases, in periodic audits |
The effective strategy combines both: automated in CI/CD to prevent regressions, manual before each release to validate the real experience.
axe-core by Deque is the most widely used accessibility testing engine. It integrates with Playwright, Cypress, Jest, and as a GitHub Action.
import { test, expect } from '@playwright/test';
import AxeBuilder from '@axe-core/playwright';
test('homepage has no accessibility violations', async ({ page }) => {
await page.goto('/');
const results = await new AxeBuilder({ page })
.withTags(['wcag2a', 'wcag2aa', 'wcag22aa'])
.analyze();
expect(results.violations).toEqual([]);
});{
"extends": ["plugin:jsx-a11y/recommended"],
"rules": {
"jsx-a11y/anchor-is-valid": "error",
"jsx-a11y/no-autofocus": "warn",
"jsx-a11y/label-has-associated-control": "error"
}
}This plugin catches issues at development time — before code reaches the browser. Combined with axe-core in CI, it covers the full automated layer.
For manual testing, VoiceOver (macOS/iOS) and NVDA (Windows) are the most widely used screen readers:
Cmd + F5 on macOSh1 → h2 → h3 hierarchy is logicalaria-live or focus managementAccessibility is not a nice-to-have — it is a legal requirement in most markets (ADA, European Accessibility Act, EN 301 549) and an engineering practice that improves quality for all users. An accessible site works better with keyboards, slow connections, small screens, and diverse devices.
From an architecture perspective, accessibility is cheaper when designed from the start. Retrofitting accessibility into an existing design system can require rewriting entire components. Integrating axe-core into CI/CD and using eslint-plugin-jsx-a11y in development prevents regressions without manual effort — but only covers 30-40% of criteria. Manual testing with screen readers remains necessary before each release.
Collection of reusable components, patterns, and guidelines ensuring visual and interaction consistency in digital products at scale.
JavaScript library for building user interfaces through declarative, reusable components, with an ecosystem spanning from SPAs to full-stack applications with Server Components.
Discipline encompassing every aspect of a person's interaction with a product, system, or service, aiming for usefulness, usability, and satisfaction.
Approaches and testing levels for validating software works correctly, from unit tests to end-to-end tests and testing in production.
Continuous Integration and Continuous Delivery/Deployment — practices that automate code integration, testing, and delivery to production. Foundation of modern software engineering.
Headless menu component for React with full accessibility, zero styles, and keyboard support. Published on npm.
Native web standards for creating reusable, encapsulated components that work in any framework or without one.