Web Development

Web Accessibility Checklist: WCAG 2.2 Compliance Guide

Web Accessibility Checklist: WCAG 2.2 Compliance Guide

Web Development March 12, 2026 · 9 min read · 2,142 words

Web Accessibility Checklist: Making Your Site WCAG 2.2 Compliant in 2026

Web accessibility is not just about compliance — it affects real people. Over 1.3 billion people worldwide live with some form of disability, according to the WHO. In the United States alone, the number of web accessibility lawsuits reached 4,605 in 2025, a 12% increase year-over-year. Beyond legal risk, accessible websites consistently see higher engagement, better SEO rankings, and broader audience reach.

WCAG 2.2, published as a W3C Recommendation in October 2023, added 9 new success criteria focused on improving accessibility for users with cognitive and motor disabilities. This comprehensive checklist covers every critical area you need to address, with practical code examples and testing strategies.

The Four WCAG Principles: POUR

WCAG is organized around four principles. Content must be:

  1. Perceivable — Users can see, hear, or otherwise perceive all content
  2. Operable — Users can navigate and interact with all interface elements
  3. Understandable — Users can comprehend the content and interface
  4. Robust — Content works with current and future assistive technologies

Perceivable: Content Everyone Can Access

Images and Non-Text Content

Every image must have appropriate alternative text. The approach differs based on the image's purpose:

<!-- Informative image: Describe the content -->
<img src="chart.png" alt="Bar chart showing Q4 revenue increased 23% to $4.2M compared to Q3">

<!-- Decorative image: Use empty alt -->
<img src="divider.svg" alt="">

<!-- Functional image (link/button): Describe the action -->
<a href="/home">
  <img src="logo.svg" alt="Acme Corp - Go to homepage">
</a>

<!-- Complex image: Provide extended description -->
<figure>
  <img src="process-flowchart.png"
       alt="Order processing workflow with 6 steps"
       aria-describedby="flowchart-desc">
  <figcaption id="flowchart-desc">
    Step 1: Customer places order. Step 2: Payment verification.
    Step 3: Inventory check. Step 4: Packing. Step 5: Shipping.
    Step 6: Delivery confirmation sent to customer.
  </figcaption>
</figure>

<!-- SVG icons: Always accessible -->
<button>
  <svg aria-hidden="true" focusable="false">
    <use href="#icon-search"></use>
  </svg>
  <span>Search</span>
</button>

Color and Contrast

WCAG 2.2 Level AA requires minimum contrast ratios:

  • Normal text: 4.5:1 contrast ratio against its background
  • Large text (18px bold or 24px regular): 3:1 contrast ratio
  • UI components and graphical objects: 3:1 contrast ratio

Never rely on color alone to convey information. Add secondary indicators:

/* Bad: Only color differentiates error state */
.error {
  color: red;
}

/* Good: Color + icon + text + border */
.error-field {
  border: 2px solid #d32f2f;
  border-left: 4px solid #d32f2f;
  background: #fef2f2;
}

.error-message {
  color: #d32f2f;
}

.error-message::before {
  content: "\26A0 "; /* Warning triangle */
}

Video and Audio Content

  • Captions are required for all prerecorded video with audio (Level A)
  • Audio descriptions are required for video where visual information is not in the dialogue (Level AA)
  • Transcripts should be provided for audio-only content
<video controls>
  <source src="demo.mp4" type="video/mp4">
  <track kind="captions" src="demo-en.vtt" srclang="en"
         label="English captions" default>
  <track kind="descriptions" src="demo-desc-en.vtt"
         srclang="en" label="English audio descriptions">
  <p>Your browser doesn't support video.
     <a href="demo-transcript.html">Read the transcript</a>.
  </p>
</video>

Operable: Interfaces Everyone Can Use

Keyboard Navigation

Every interactive element must be operable with a keyboard alone. Test your entire site using only Tab, Shift+Tab, Enter, Space, Escape, and Arrow keys.

<!-- Custom button: Must be keyboard accessible -->
<!-- Bad: div is not focusable or activatable by keyboard -->
<div onclick="doSomething()">Click me</div>

<!-- Good: Use semantic HTML -->
<button type="button" onclick="doSomething()">Click me</button>

<!-- If you MUST use a non-semantic element: -->
<div role="button" tabindex="0"
     onclick="doSomething()"
     onkeydown="if(event.key==='Enter'||event.key===' ')doSomething()">
  Click me
</div>

Focus Management

Focus indicators must be visible and meet WCAG 2.2's enhanced requirements (Success Criterion 2.4.13, Level AAA, but widely recommended at AA):

/* Remove default only if replacing with better indicator */
:focus {
  outline: none;
}

/* Custom focus indicator meeting WCAG 2.2 */
:focus-visible {
  outline: 3px solid #2563eb;
  outline-offset: 2px;
  border-radius: 2px;
}

/* Ensure focus is visible on dark backgrounds too */
.dark-section :focus-visible {
  outline-color: #93c5fd;
  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.5);
}

New in WCAG 2.2: Focus Not Obscured (2.4.11 / 2.4.12)

When an element receives keyboard focus, it must not be fully hidden by sticky headers, footers, or overlapping content. This is a new Level AA criterion:

/* Ensure focused elements scroll into view above sticky header */
.sticky-header {
  position: sticky;
  top: 0;
  z-index: 100;
  height: 64px;
}

/* Use scroll-padding to account for sticky header */
html {
  scroll-padding-top: 80px; /* Header height + buffer */
}

/* For modals: trap focus inside */
function trapFocus(modal) {
  const focusableElements = modal.querySelectorAll(
    'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
  );
  const firstFocusable = focusableElements[0];
  const lastFocusable = focusableElements[focusableElements.length - 1];

  modal.addEventListener('keydown', (e) => {
    if (e.key !== 'Tab') return;

    if (e.shiftKey && document.activeElement === firstFocusable) {
      e.preventDefault();
      lastFocusable.focus();
    } else if (!e.shiftKey && document.activeElement === lastFocusable) {
      e.preventDefault();
      firstFocusable.focus();
    }
  });

  firstFocusable.focus();
}

New in WCAG 2.2: Target Size (2.5.8 Level AA)

Interactive targets must be at least 24x24 CSS pixels, with some exceptions. This is critical for users with motor impairments:

/* Ensure all interactive elements meet minimum target size */
button,
a,
input[type="checkbox"],
input[type="radio"],
select {
  min-height: 44px; /* Exceeds the 24px minimum, targets 44px recommendation */
  min-width: 44px;
}

/* For inline links in text, spacing provides adequate target */
p a {
  min-height: auto;
  min-width: auto;
  /* Adequate spacing between inline targets is acceptable */
}

/* Touch targets for mobile should be even larger */
@media (pointer: coarse) {
  button, a {
    min-height: 48px;
    min-width: 48px;
    padding: 12px 16px;
  }
}

Understandable: Clear Content and Predictable Behavior

Page Language

Always declare the language of your page and any content in a different language:

<html lang="en">
  <body>
    <p>This text is in English.</p>
    <blockquote lang="fr">
      La vie est belle.
    </blockquote>
  </body>
</html>

Form Labels and Error Handling

Every form input must have a visible label. Error messages must be specific and helpful:

<form novalidate>
  <div>
    <label for="email">Email address <span aria-hidden="true">*</span></label>
    <input type="email" id="email" name="email"
           required
           aria-required="true"
           aria-describedby="email-hint email-error"
           aria-invalid="false">
    <span id="email-hint">We'll never share your email.</span>
    <span id="email-error" role="alert" hidden></span>
  </div>

  <div>
    <label for="password">Password <span aria-hidden="true">*</span></label>
    <input type="password" id="password" name="password"
           required
           aria-required="true"
           aria-describedby="password-req password-error"
           minlength="8">
    <span id="password-req">Minimum 8 characters, at least one number and one uppercase letter.</span>
    <span id="password-error" role="alert" hidden></span>
  </div>

  <button type="submit">Create account</button>
</form>

<script>
// Show specific, actionable error messages
function showError(input, message) {
  const errorEl = document.getElementById(input.id + '-error');
  errorEl.textContent = message;
  errorEl.hidden = false;
  input.setAttribute('aria-invalid', 'true');
}

// Good error: "Email must include an @ symbol (e.g., [email protected])"
// Bad error: "Invalid input"
</script>

New in WCAG 2.2: Redundant Entry (3.3.7 Level A)

Users should not have to re-enter information they already provided in the same process. This is critical for users with cognitive disabilities:

  • Auto-populate shipping address from billing address
  • Pre-fill form fields from user profile data
  • Allow users to select previously entered information
  • Carry information forward through multi-step processes

New in WCAG 2.2: Accessible Authentication (3.3.8 Level AA)

Authentication processes must not rely on cognitive function tests (puzzles, memory tasks) unless an alternative is provided:

  • Allow password managers — do not block paste in password fields
  • Provide alternative login methods — passkeys, magic links, social login alongside CAPTCHA
  • If CAPTCHA is required — offer multiple types (image + audio + puzzle) and support third-party solvers
<!-- DO NOT block paste - this fails WCAG 2.2 -->
<!-- Bad: -->
<input type="password" onpaste="return false">

<!-- Good: Allow paste and password managers -->
<input type="password" autocomplete="current-password">

<!-- Provide alternative to CAPTCHA -->
<div>
  <!-- Primary: invisible hCaptcha -->
  <div id="captcha"></div>
  <!-- Alternative: email verification link -->
  <p>Having trouble? <a href="/auth/email-verify">Verify via email instead</a>.</p>
</div>

Robust: Works With Assistive Technology

Semantic HTML: Your First Line of Defense

Using semantic HTML elements correctly provides the most accessibility for the least effort:

<!-- Use semantic landmarks -->
<header> instead of <div id="header">
<nav> instead of <div id="navigation">
<main> instead of <div id="content">
<aside> instead of <div id="sidebar">
<footer> instead of <div id="footer">

<!-- Correct heading hierarchy -->
<h1>Page Title</h1>        <!-- One per page -->
  <h2>Section</h2>
    <h3>Subsection</h3>
    <h3>Subsection</h3>
  <h2>Section</h2>
    <h3>Subsection</h3>

<!-- Use lists for groups of related items -->
<ul> for unordered lists
<ol> for ordered/sequential lists
<dl> for definition/description lists

ARIA: When HTML Is Not Enough

Use ARIA attributes only when semantic HTML cannot convey the information. The first rule of ARIA: don't use ARIA if you can use native HTML.

<!-- Tab interface (no native HTML equivalent) -->
<div role="tablist" aria-label="Product information">
  <button role="tab" id="tab-1" aria-selected="true"
          aria-controls="panel-1">Description</button>
  <button role="tab" id="tab-2" aria-selected="false"
          aria-controls="panel-2" tabindex="-1">Reviews</button>
  <button role="tab" id="tab-3" aria-selected="false"
          aria-controls="panel-3" tabindex="-1">Specifications</button>
</div>

<div role="tabpanel" id="panel-1" aria-labelledby="tab-1">
  <p>Product description content...</p>
</div>
<div role="tabpanel" id="panel-2" aria-labelledby="tab-2" hidden>
  <p>Review content...</p>
</div>

<!-- Live region for dynamic updates -->
<div aria-live="polite" aria-atomic="true">
  <!-- Screen reader announces changes here -->
  <p>3 items added to cart</p>
</div>

Testing Your Accessibility

Automated Testing Tools

Automated tools catch approximately 30-40% of accessibility issues. Use them as a first pass:

  • axe DevTools (browser extension) — the industry standard, catches WCAG violations with clear explanations
  • Lighthouse Accessibility audit — built into Chrome DevTools
  • WAVE (wave.webaim.org) — visual overlay showing issues in context
  • Pa11y — CLI tool for CI/CD pipeline integration
# Add Pa11y to your CI pipeline
npm install -D pa11y-ci

# .pa11yci.json configuration
{
  "defaults": {
    "standard": "WCAG2AA",
    "timeout": 10000,
    "wait": 1000
  },
  "urls": [
    "http://localhost:3000/",
    "http://localhost:3000/products",
    "http://localhost:3000/contact"
  ]
}

# Run in CI
npx pa11y-ci

Manual Testing Checklist

Automated tools cannot replace manual testing. Perform these checks on every page:

  1. Keyboard-only navigation: Tab through the entire page. Can you reach and operate every interactive element?
  2. Screen reader testing: Use NVDA (Windows, free), VoiceOver (macOS/iOS, built-in), or TalkBack (Android, built-in)
  3. Zoom to 200%: Is all content still visible and functional? No horizontal scrolling required?
  4. High contrast mode: Enable Windows High Contrast or use forced-colors: active media query
  5. Reduced motion: Enable prefers-reduced-motion and verify animations stop or simplify
/* Respect user's motion preferences */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

Quick Reference: WCAG 2.2 Compliance Checklist

Use this condensed checklist as a final review before launch:

  • All images have appropriate alt text (or empty alt for decorative)
  • Color contrast meets 4.5:1 for text, 3:1 for large text and UI components
  • All interactive elements are keyboard accessible with visible focus indicators
  • Target sizes are at least 24x24 CSS pixels (WCAG 2.2)
  • Focus is never obscured by sticky elements (WCAG 2.2)
  • Forms have visible labels, specific error messages, and no paste restrictions
  • Authentication does not require cognitive tests without alternatives (WCAG 2.2)
  • Users don't re-enter previously provided information (WCAG 2.2)
  • Page language is declared with lang attribute
  • Heading hierarchy is logical (h1 → h2 → h3, no skipped levels)
  • Landmark regions are used (header, nav, main, footer)
  • Videos have captions and audio descriptions
  • Animations respect prefers-reduced-motion
  • Content reflows at 200% zoom without horizontal scrolling

Accessibility is not a one-time task. Integrate it into your development workflow from the start. Include accessibility criteria in your definition of done, add automated tests to your CI pipeline, and schedule regular manual audits. The result is a better experience for all users, not just those with disabilities.

wcag 2.2 checklist web accessibility guide wcag compliance 2026 accessible website development

About the Author

C
Casey Morgan
Managing Editor, TrendVidStream
Casey Morgan is the managing editor at TrendVidStream, specializing in technology, entertainment, gaming, and digital culture. With extensive experience in content curation and editorial analysis, Casey leads our coverage of trending topics across multiple regions and categories.

Related Articles