WCAG 2.2 (Web Content Accessibility Guidelines) is the current standard for web accessibility, organized around four principles: perceivable, operable, understandable, and robust. This checklist distills its requirements into actionable items for developers.

Accessibility is not optional — it is a legal requirement in many jurisdictions and, more importantly, a matter of ensuring your application is usable by everyone. Approximately 15% of the world’s population lives with some form of disability. Building accessible web applications is not charity; it is good engineering.

Perceivable: Users Can See or Hear Content

Color Contrast

Insufficient contrast is the most common accessibility failure. Text must have enough contrast against its background to be readable by people with low vision or color blindness.

WCAG requirements:

Element AA (minimum) AAA (enhanced)
Normal text (<18px or <14px bold) 4.5:1 7:1
Large text (18px+ or 14px+ bold) 3:1 4.5:1
UI components and icons 3:1

Common failures:

  • Light gray text on white backgrounds (#999 on #fff = 2.85:1, fails AA)
  • Placeholder text that is too faint
  • Disabled state styling that removes all contrast
  • Links that are only distinguished by color (also add underline or other visual indicator)

You can verify contrast ratios with our WCAG Contrast Checker. Enter foreground and background colors and it shows the ratio, whether it passes AA and AAA for both normal and large text, and suggests adjustments if it fails.

Text Alternatives

Every non-decorative image needs a text alternative:

<!-- Informative image -->
<img src="chart.png" alt="Sales increased 40% from Q1 to Q2 2026">

<!-- Decorative image -->
<img src="divider.svg" alt="" role="presentation">

<!-- Complex image with extended description -->
<figure>
  <img src="architecture.svg" alt="System architecture diagram">
  <figcaption>
    The system uses a microservices architecture with an API gateway...
  </figcaption>
</figure>

Guidelines for alt text:

  • Describe the content and function, not the appearance (“Submit form” not “green button”)
  • Keep it concise (under 150 characters)
  • Do not start with “Image of” or “Photo of” — screen readers already announce it as an image
  • For icons with labels, use alt="" or aria-hidden="true" to avoid redundancy

If you are stuck describing an image, our Alt Text Generator can draft a starting description you edit for accuracy and context.

Video and Audio

  • Provide captions for video content
  • Provide transcripts for audio content
  • Do not autoplay audio — users with screen readers hear both the audio and their screen reader simultaneously
  • Provide audio descriptions for video when the visual content conveys information not in the dialogue

Responsive Design

Content must be usable at 200% zoom and at a 320px viewport width (equivalent to 1280px at 400% zoom). This means:

  • No horizontal scrolling at 320px width for vertical content
  • Text remains readable when zoomed to 200%
  • No content is hidden or cut off
  • Touch targets are at least 24x24 CSS pixels (WCAG 2.2 requirement)

Operable: Users Can Interact with the Interface

Keyboard Navigation

Everything clickable must be keyboard-accessible:

<!-- Good: naturally keyboard-accessible -->
<button onclick="save()">Save</button>
<a href="/settings">Settings</a>

<!-- Bad: not keyboard-accessible without extra work -->
<div onclick="save()">Save</div>
<span class="link" onclick="navigate()">Settings</span>

Use native HTML elements whenever possible. <button>, <a>, <input>, <select> — these are keyboard-accessible by default. Custom widgets built with <div> and <span> require manual keyboard handling.

Keyboard checklist:

  • All interactive elements are reachable with Tab
  • Tab order follows a logical reading sequence
  • Focus is visible (never use outline: none without a replacement)
  • Custom widgets support expected keyboard patterns (Escape to close modals, Arrow keys in menus)
  • No keyboard traps — users can always Tab away from a component

Focus Management

/* Bad: removes focus indicator entirely */
*:focus { outline: none; }

/* Good: custom focus indicator */
*:focus-visible {
  outline: 2px solid #3498db;
  outline-offset: 2px;
}

Use :focus-visible instead of :focus for custom styles. :focus-visible only shows the focus ring for keyboard navigation, not mouse clicks, giving you the best of both worlds.

To confirm your tab order actually follows a logical reading sequence, our Focus Order Visualizer walks through a page and highlights each focusable element in order.

Allow keyboard users to skip past repeated navigation:

<body>
  <a href="#main-content" class="skip-link">Skip to main content</a>
  <nav><!-- navigation --></nav>
  <main id="main-content">
    <!-- page content -->
  </main>
</body>
.skip-link {
  position: absolute;
  top: -40px;
  left: 0;
  padding: 8px;
  z-index: 100;
}

.skip-link:focus {
  top: 0;
}

Motion and Animation

Some users experience motion sickness from animations:

@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

Respect the user’s operating system preference. Essential animations (like a loading spinner) can be retained; decorative or large-scale animations should be removed.

Understandable: Content Is Clear

Semantic HTML

Use HTML elements for their intended purpose:

<!-- Correct semantic structure -->
<header>
  <nav aria-label="Main navigation">
    <ul>
      <li><a href="/">Home</a></li>
      <li><a href="/about">About</a></li>
    </ul>
  </nav>
</header>

<main>
  <h1>Page Title</h1>
  <section aria-labelledby="features-heading">
    <h2 id="features-heading">Features</h2>
    <p>Content here.</p>
  </section>
</main>

<footer>
  <p>Copyright 2026</p>
</footer>

Landmark elements (<header>, <nav>, <main>, <footer>, <aside>, <section>) allow screen reader users to jump between page regions. A page without landmarks forces users to navigate through every element sequentially.

Heading Hierarchy

Headings must follow a logical hierarchy — do not skip levels:

<!-- Good -->
<h1>Product Page</h1>
  <h2>Description</h2>
  <h2>Reviews</h2>
    <h3>Customer Reviews</h3>
    <h3>Expert Reviews</h3>

<!-- Bad: skipping from h1 to h3 -->
<h1>Product Page</h1>
  <h3>Description</h3>

Screen reader users navigate by headings. A logical hierarchy creates a navigable document outline. Our Heading Hierarchy Checker scans a page and flags skipped or out-of-order heading levels.

Forms

Forms are a critical accessibility area:

<!-- Every input needs a label -->
<label for="email">Email address</label>
<input type="email" id="email" name="email" required
       aria-describedby="email-hint email-error">
<p id="email-hint">We'll never share your email.</p>
<p id="email-error" role="alert" hidden>Please enter a valid email.</p>

Form checklist:

  • Every input has a visible <label> with matching for/id
  • Required fields are indicated (not just by color)
  • Error messages identify the field and describe how to fix the error
  • Error messages are announced by screen readers (role="alert" or aria-live="assertive")
  • Group related fields with <fieldset> and <legend>

Language

Specify the page language and any language changes:

<html lang="en">
  <body>
    <p>This is English text.</p>
    <p>The French word <span lang="fr">bonjour</span> means hello.</p>
  </body>
</html>

Screen readers use the language attribute to switch pronunciation rules.

Robust: Content Works Across Technologies

ARIA: When Semantic HTML Is Not Enough

ARIA (Accessible Rich Internet Applications) adds accessibility information to custom widgets. But the first rule of ARIA is: do not use ARIA if native HTML can do the job.

<!-- Unnecessary ARIA -->
<div role="button" tabindex="0" aria-label="Save">Save</div>

<!-- Just use a button -->
<button>Save</button>

When you do need ARIA, learn the common roles and reference the correct usage. Our ARIA Roles Reference provides a quick lookup for all ARIA roles, states, and properties with usage examples and requirements. For a deeper walkthrough of patterns like live regions, tabs, and modals, see our ARIA accessibility guide.

Common ARIA patterns:

<!-- Expandable section -->
<button aria-expanded="false" aria-controls="panel1">Details</button>
<div id="panel1" hidden>Panel content</div>

<!-- Live region (announces changes) -->
<div aria-live="polite">3 items in cart</div>

<!-- Modal dialog -->
<div role="dialog" aria-modal="true" aria-labelledby="dialog-title">
  <h2 id="dialog-title">Confirm deletion</h2>
  <p>Are you sure?</p>
  <button>Cancel</button>
  <button>Delete</button>
</div>

Color and Accessibility

Beyond contrast ratios, ensure your color palette works for users with color vision deficiency. Our Color-Safe Palette tool generates palettes that maintain distinguishability across common types of color blindness, showing simulated views for deuteranopia, protanopia, and tritanopia.

How to Test for Accessibility

Automated Testing

Automated tools catch about 30-40% of accessibility issues:

# Axe-core via CLI
npx @axe-core/cli https://yoursite.com

# Lighthouse accessibility audit
npx lighthouse https://yoursite.com --only-categories=accessibility

Manual Testing

The other 60-70% requires manual testing:

  1. Keyboard test: Navigate your entire page using only Tab, Enter, Space, Escape, and Arrow keys
  2. Screen reader test: Use VoiceOver (Mac), NVDA (Windows), or Orca (Linux)
  3. Zoom test: Increase browser zoom to 200% and verify nothing breaks
  4. Reduced motion test: Enable “Reduce motion” in your OS settings

Quick Audit Checklist

  • All images have appropriate alt text
  • Color contrast meets WCAG AA minimums
  • All functionality is keyboard-accessible
  • Focus indicators are visible
  • Headings follow a logical hierarchy
  • Form inputs have labels
  • Error messages are clear and associated with fields
  • Page has proper landmark regions
  • Language is specified on the html element
  • Animations respect prefers-reduced-motion

Accessibility is not a feature you add at the end — it is a quality that is built in from the start. Every item on this checklist is simpler to implement during initial development than to retrofit later. Start with semantic HTML, test with your keyboard, and iterate from there.