Web accessibility is not optional — it is a fundamental requirement for building inclusive digital experiences. Over one billion people worldwide live with some form of disability, and accessible design benefits everyone, not just those with permanent impairments.
Captions help someone watching a video on a train. Strong contrast helps someone reading a phone in sunlight. Keyboard support helps the power user and the person whose wrist is in a cast this month.
This guide covers the standard, the patterns that solve most real problems, and a testing routine that fits into normal development.
Understanding WCAG
The Web Content Accessibility Guidelines (WCAG) provide a framework for making web content perceivable, operable, understandable, and robust. The four principles — often abbreviated as POUR — serve as the foundation for all accessibility standards.
Key success criteria include providing text alternatives for non-text content, ensuring sufficient color contrast ratios, making all functionality available from a keyboard, and offering multiple ways to navigate content.
Levels and versions
Every success criterion is assigned a level: A, AA, or AAA. Level AA is the practical target for most organizations and the level most procurement requirements and accessibility policies point to. AAA is not achievable for all content, so treat it as a stretch goal for specific pages.
WCAG 2.2 became a W3C Recommendation in October 2023. It builds on 2.1 rather than replacing it, so work done against the older version carries over. One criterion, 4.1.1 Parsing, was removed as obsolete. If you are starting a new project, target WCAG 2.2 AA.
What WCAG 2.2 added
The new criteria are worth knowing by name because they catch problems that older checklists miss:
- 2.4.11 Focus Not Obscured (Minimum), AA — a focused element must not be completely hidden by author-created content such as a sticky header or cookie banner.
- 2.5.7 Dragging Movements, AA — anything done by dragging, such as reordering a list or moving a slider, needs a single-pointer alternative.
- 2.5.8 Target Size (Minimum), AA — pointer targets should be at least 24 by 24 CSS pixels, or have enough spacing around them, with a handful of listed exceptions.
- 3.2.6 Consistent Help, A — help mechanisms that repeat across pages appear in the same relative order.
- 3.3.7 Redundant Entry, A — do not make people re-enter information they already provided in the same process.
- 3.3.8 Accessible Authentication (Minimum), AA — logging in must not depend on a cognitive function test like remembering or transcribing a code, unless an alternative or assistance (such as allowing paste and password managers) is available.
The remaining three new criteria (2.4.12, 2.4.13 and 3.3.9) are at level AAA.
Common Accessibility Patterns
Start with semantic HTML. Using the correct heading hierarchy, landmark elements, and form labels addresses a significant portion of accessibility requirements. ARIA attributes should supplement native HTML semantics, not replace them.
Prefer native elements
A button element is focusable, activates on Enter and Space, exposes the button role, and participates in forms. A div with a click handler does none of that until you rebuild it by hand, and most hand-built versions miss something.
<!-- Avoid: needs role, tabindex, and key handlers to approach parity -->
<div class="btn" onclick="save()">Save</div>
<!-- Prefer: keyboard, focus, and semantics included -->
<button type="button" onclick="save()">Save</button>
The same applies to links (a with an href for navigation, button for actions), details and summary for disclosure, and dialog for modals. When no native element fits, follow the WAI-ARIA Authoring Practices Guide rather than inventing a keyboard model.
Landmarks and headings
Screen reader users commonly navigate by landmarks and headings rather than reading top to bottom. Give every page one main, wrap site navigation in nav, and use header and footer for page-level banners. If you have more than one nav, give each an aria-label so they can be told apart.
Headings should describe the structure of the content, not its visual size. Do not skip from h2 to h4 because the smaller style looked better; change the style instead.
Forms
Every input needs a programmatically associated label. Placeholder text is not a label: it disappears on input and often fails contrast. Group related controls with fieldset and legend, and connect hints and errors to their fields:
<label for="email">Email address</label>
<input id="email" type="email" autocomplete="email"
aria-describedby="email-hint email-error" aria-invalid="true">
<p id="email-hint">We will only use this to send your receipt.</p>
<p id="email-error">Enter an email address in the format name@example.com.</p>
Error messages should say what went wrong and how to fix it. On submit, move focus to an error summary or the first invalid field so keyboard and screen reader users are not left guessing. The autocomplete attribute also matters: it satisfies 1.3.5 Identify Input Purpose and reduces typing for everyone.
Focus management
Focus management is critical for single-page applications. When content changes dynamically, ensure focus moves predictably so screen reader users understand what has changed. Use aria-live regions to announce dynamic updates.
A few rules cover most cases:
- After a client-side route change, move focus to the new page’s main heading or main region, and update the document title.
- When a modal opens, move focus into it and keep it there; when it closes, return focus to the control that opened it. The native
dialogelement opened withshowModal()handles much of this for you. - Never remove the focus indicator without replacing it. Use
:focus-visibleto show a clear ring for keyboard users without showing it on every mouse click. - Live regions must exist in the DOM before their content changes, or many screen readers will not announce the update. Use
aria-live="polite"for status messages and reserveassertivefor genuinely urgent ones.
Color and contrast
Normal text needs a contrast ratio of at least 4.5:1 against its background, and large text (roughly 18pt, or 14pt bold) needs 3:1 (1.4.3). User interface components and meaningful graphics, such as input borders, focus rings and chart lines, need 3:1 against adjacent colors (1.4.11). Check both light and dark themes; a palette that passes in one often fails in the other.
Color must never be the only way information is conveyed (1.4.1). A red border on an invalid field should be accompanied by an icon or text; a chart series should be distinguishable by label, pattern or position as well as hue.
Motion and zoom
Respect the user’s motion preference. Large parallax and auto-playing animation can cause real discomfort for people with vestibular disorders.
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
Content should also reflow without horizontal scrolling at a width of 320 CSS pixels (1.4.10), which is what a 1280-pixel window looks like at 400% zoom. Use relative units for type, avoid fixed heights on text containers, and never disable pinch zoom in the viewport meta tag.
Testing Your Work
Automated tools like axe-core and Lighthouse catch only a portion of accessibility issues. They are excellent at objective checks such as missing labels, invalid ARIA and contrast failures, but they cannot tell you whether alt text is meaningful, whether focus order makes sense, or whether an interaction is understandable. Manual testing with keyboard navigation and screen readers (VoiceOver, NVDA, JAWS) is essential for catching the rest. Include people with disabilities in your user research for the most accurate feedback.
A routine that fits into development
- Lint and unit tests. Run an accessibility linter for your framework and add automated axe checks to component and end-to-end tests so regressions fail the build.
- Keyboard pass. Unplug the mouse. Tab through the page: can you reach and operate every control, is the focus indicator always visible, and is the order logical?
- Zoom and reflow. Zoom to 200% and 400%. Nothing should overlap, truncate or require two-dimensional scrolling.
- Screen reader spot check. Pick the critical path — sign up, checkout, the main dashboard — and complete it with a screen reader. Listen for unlabeled buttons, unannounced errors and confusing reading order.
- Preference checks. Toggle reduced motion, forced colors (Windows High Contrast) and dark mode, and confirm nothing important disappears.
Making It Stick
Accessibility usually fails through drift: a feature added months later quietly breaks a focus trap. A few habits prevent that:
- Put accessibility acceptance criteria in tickets, not in a separate audit backlog.
- Bake the patterns into shared components so product teams get correct behavior by default.
- Publish an accessibility statement that says what you conform to, what known issues remain, and how people can report problems.
Building accessible websites is an ongoing commitment, but the tools and patterns available today make it achievable for every development team. Start with semantic HTML, test with a keyboard every time you ship, and treat each accessibility bug with the same seriousness as any other defect that locks users out.