LUCKY.GRAPHICS
guides

WCAG 2026: A Complete Accessibility Compliance Guide for Designers and Developers

Everything you need to pass WCAG 2.2 AA compliance in 2026. Color contrast, keyboard navigation, screen reader optimization, and ARIA patterns explained with real code.

Lucky Graphics ArchiveJanuary 21, 202618 min read

WCAG 2.2 Compliance: A Complete Guide for 2026

Short Answer: Everything you need to pass WCAG 2.2 AA compliance in 2026. Color contrast, keyboard navigation, screen reader optimization, and ARIA patterns explained with real code.

The word "accessibility" in product meetings often gets filed under "nice to have." This is wrong on three counts.

First, it's wrong legally. In the United States, the ADA (Americans with Disabilities Act) has been interpreted to apply to websites, and enforcement has increased sharply since 2023. The EU's European Accessibility Act came into full force for most digital services in 2025. WCAG 2.2 AA is now effectively the legal baseline in most developed markets.

Second, it's wrong commercially. Approximately 1 in 6 people worldwide has some form of disability. More practically: many accessibility features benefit everyone — captions help people watching in noisy environments; high-contrast UI benefits outdoor mobile users; keyboard navigation is actively used by power users who never use a mouse.

Third, it's wrong ethically. This shouldn't need explaining. Building software that excludes people with disabilities is building software that other users happen to be able to use despite its flaws.

This guide is a practical implementation reference for WCAG 2.2 AA compliance, organized by the four POUR principles. We'll cover what each criterion means, why it matters, and how to implement or test it.


The POUR Framework

WCAG is organized around four core principles:

Perceivable — Information and UI components must be presentable to users in ways they can perceive. Content can't be invisible to all their senses.

Operable — UI components and navigation must be operable. All functionality must be available from a keyboard.

Understandable — Information and UI operation must be understandable. Content and interfaces must communicate clearly.

Robust — Content must be robust enough to be reliably interpreted by a wide variety of user agents, including assistive technologies.


Perceivability

Text Contrast Ratios

WCAG 2.2 AA requires:

  • 4.5:1 contrast ratio for normal text (< 18pt or < 14pt bold)
  • 3:1 contrast ratio for large text (≥ 18pt or ≥ 14pt bold) and UI components

This sounds technical but is straightforward in practice. The contrast ratio is computed from the relative luminance of the foreground and background colors. You never need to calculate this manually — use tooling.

Testing Tools:

  • WebAIM Contrast Checker — Paste your hex codes, get the ratio
  • Chrome DevTools Accessibility Pane — Shows contrast ratio for selected elements
  • Figma Stark Plugin — In-design contrast checking during the design phase

Common failures:

  • Light gray placeholder text on white inputs (#999999 on #FFFFFF = 2.85:1)
  • Blue links on dark backgrounds that "feel" fine but fail at 2:1
  • Disabled button text that is intentionally low-contrast — the exception for disabled elements in WCAG 2.1 is removed in WCAG 2.2; disabled elements still need 3:1
/* Commonly failing input placeholder */
input::placeholder {
  color: #767676; /* Exactly 4.54:1 on white — passing minimum */
  /* NOT #999999 — that's only 2.85:1, a failure */
}

Non-Text Alternatives

Every meaningful image requires alternative text. The key distinction: meaningful vs. decorative.

Meaningful images convey information integral to the content. Decorative images are purely visual ornaments. Decorative images should use empty alt text (alt="") — this tells screen readers to ignore the image entirely rather than reading the file name.

<!-- Meaningful image: alt describes what it shows -->
<img
  src="/charts/q4-revenue.png"
  alt="Bar chart showing Q4 2025 revenue of $2.3M, up 18% year-over-year"
/>

<!-- Decorative image: alt is intentionally empty -->
<img src="/decorative-wave.svg" alt="" aria-hidden="true" />

<!-- Icon with text label: icon is decorative, text provides the label -->
<button>
  <svg aria-hidden="true" focusable="false">...</svg>
  Save draft
</button>

<!-- Icon-only button: icon IS the label -->
<button aria-label="Save draft">
  <svg aria-hidden="true" focusable="false">...</svg>
</button>

Captions and Transcripts

All audio content must have captions. All video must have synchronized captions. All prerecorded audio-only content (podcasts, audio guides) must have a text transcript.

In 2026, automatic captioning (via Whisper or similar) is good enough for initial draft captions, but human review is still required for:

  • Content with technical jargon or proper nouns
  • Content with overlapping speakers
  • Content with significant background noise

Operability

Keyboard Navigation

Every function available via mouse must be available via keyboard. This is non-negotiable. The practical implementation requires:

Focus management for dynamic content:

When a modal opens, focus must move into it. When it closes, focus must return to the trigger. This doesn't happen automatically — you must manage it in code.

function openModal(modalElement, triggerElement) {
  modalElement.removeAttribute('hidden');
  modalElement.setAttribute('aria-modal', 'true');
  
  // Find and focus the first interactive element inside the modal
  const firstFocusable = modalElement.querySelector(
    'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
  );
  firstFocusable?.focus();
  
  // Store trigger for return focus
  modalElement._triggerElement = triggerElement
};
function closeModal(modalElement) {
  modalElement.setAttribute('hidden', '');
  
  // Return focus to the element that triggered the modal
  modalElement._triggerElement?.focus()
};

Focus trap in modals:

When a modal is open, keyboard Tab must cycle within it — not into the page content behind it. Implement a focus trap:

function trapFocus(element) {
  const focusableEls = element.querySelectorAll(
    'a[href], button:not([disabled]), textarea, input, select, [tabindex="0"]'
  );
  
  const firstEl = focusableEls[0];
  const lastEl = focusableEls[focusableEls.length - 1];
  
  element.addEventListener('keydown', (e) => {
    if (e.key !== 'Tab') return;
    
    if (e.shiftKey) {
      // Shift+Tab: going backward
      if (document.activeElement === firstEl) {
        lastEl.focus();
        e.preventDefault()
};
    } else {
      // Tab: going forward
      if (document.activeElement === lastEl) {
        firstEl.focus();
        e.preventDefault()
};
    }
  })
};

Focus indicator visibility (WCAG 2.2 2.4.11/2.4.12):

WCAG 2.2 added two new criteria requiring that focus indicators have a minimum area of the component perimeter and meet a 3:1 contrast ratio against adjacent colors. The browser default blue outline is typically insufficient.

/* Custom focus indicator that meets WCAG 2.2 criteria */
:focus-visible {
  outline: 3px solid #005FCC;     /* High contrast against white */
  outline-offset: 2px;             /* Space between element and outline */
  border-radius: 2px;              /* Follows element shape */
}

/* Remove outline for mouse users (they see :hover state) */
:focus:not(:focus-visible) {
  outline: none
};

Do not use outline: none without a replacement. This fails WCAG at the most fundamental keyboard navigation level.

Touch Target Size (WCAG 2.2 2.5.8)

WCAG 2.2 added criterion 2.5.8: Target Size (Minimum). Interactive targets must be at least 24×24 CSS pixels, with the exception of elements in a line of text.

The adjacent target spacing rule: if a 24×24px target is adjacent to another target, the combined "spacing offset" must total 24px. In practice, this means either making targets 44×44px minimum (Apple's HIG recommendation) or ensuring adequate spacing between targets.

/* Safe minimum — exceeds WCAG 2.5.8 requirement */
.interactive-target {
  min-width: 44px;
  min-height: 44px;
  cursor: pointer
};
/* When visual size must be smaller, extend the touch target with padding */
.small-icon-button {
  width: 16px;
  height: 16px;
  /* Padding extends the hit area without affecting visual size */
  padding: 14px;
  /* Compensate visually */
  margin: -14px
};

Understandability

Language Declaration

Every page must declare its language. Screen readers use this to select the correct pronunciation engine:

<html lang="en">  <!-- English -->
<html lang="fr">  <!-- French -->
<html lang="zh-Hant">  <!-- Traditional Chinese -->

If a passage of text uses a different language from the page default, declare it:

<p>She replied in French: <span lang="fr">je ne sais pas</span></p>

Error Identification and Description

When form errors occur, WCAG requires:

  • The error field is identified (not just highlighted in red)
  • The error is described in text
  • Where possible, a correction is suggested
<label for="email">Email address</label>
<input
  type="email"
  id="email"
  name="email"
  aria-required="true"
  aria-describedby="email-error"
  aria-invalid="true"
/>
<p id="email-error" role="alert">
  Please enter a valid email address (example: name@domain.com)
</p>

The role="alert" ensures the error is announced immediately by screen readers without the user having to navigate to it.


Robustness: ARIA Patterns

ARIA (Accessible Rich Internet Applications) is the specification for augmenting HTML with additional semantic meaning for accessibility. Three rules govern its use:

Rule 1: Use native HTML before ARIA. A <button> is always better than <div role="button">. Native elements are already understood by all assistive technologies.

Rule 2: Never change the semantics of native elements. Don't add role="heading" to a <button>. Don't add role="button" to an <h1>.

Rule 3: All interactive ARIA controls must support keyboard interactions from the ARIA spec. A role="combobox" must support arrow keys, Home, End, Enter, Escape per the ARIA Authoring Practices Guide.

Here's a reference for the most common patterns:

<!-- Combobox (autocomplete) -->
<div role="combobox" aria-expanded="true" aria-haspopup="listbox" aria-controls="options-list">
  <input type="text" aria-autocomplete="list" aria-activedescendant="option-3" />
</div>
<ul id="options-list" role="listbox">
  <li id="option-1" role="option">Red</li>
  <li id="option-2" role="option">Green</li>
  <li id="option-3" role="option" aria-selected="true">Blue</li>
</ul>

<!-- Toggle button -->
<button aria-pressed="false" onclick="this.setAttribute('aria-pressed', this.getAttribute('aria-pressed') === 'false')">
  Enable notifications
</button>

<!-- Tab interface -->
<div role="tablist" aria-label="Account settings">
  <button role="tab" aria-selected="true" aria-controls="profile-panel" id="profile-tab">Profile</button>
  <button role="tab" aria-selected="false" aria-controls="security-panel" id="security-tab">Security</button>
</div>
<div role="tabpanel" id="profile-panel" aria-labelledby="profile-tab">...</div>
<div role="tabpanel" id="security-panel" aria-labelledby="security-tab" hidden>...</div>

Testing Your Implementation

Manual testing is required — automated tools catch only ~30–40% of accessibility issues.

Automated audit baseline:

  1. Run Lighthouse Accessibility audit in Chrome DevTools
  2. Run axe DevTools browser extension — more thorough than Lighthouse
  3. Run Pa11y in CI: npx pa11y https://yoursite.com --standard WCAG2AA

Manual keyboard test:

  1. Disconnect your mouse
  2. Tab through every interactive element on the page
  3. Verify every element receives a visible focus indicator
  4. Verify modal focus management (open → focus trap → close → return to trigger)
  5. Verify all dropdowns and custom components respond to arrow keys

Screen reader testing:

  • macOS: VoiceOver (built in, activate with Cmd+F5)
  • Windows: NVDA (free) with Firefox, or JAWS
  • iOS: VoiceOver (built in)
  • Android: TalkBack (built in)

Test core user journeys: navigate to main content, fill in a form and submit, navigate a data table, interact with a modal.


WCAG 2.2 AA Compliance Checklist

  • All text at 4.5:1 contrast minimum (3:1 for large text)
  • All meaningful images have descriptive alt text; decorative images use alt=""
  • All video has synchronized captions; all audio has transcript
  • Modal focus managed: focus enters on open, returns to trigger on close
  • Focus trap implemented in open modals
  • lang attribute on <html> element and on any non-English passage
  • All interactive elements accessible via keyboard
  • :focus-visible indicator provides 3:1 contrast and meets minimum area requirement
  • Interactive targets are minimum 24×24px (recommend 44×44px)
  • Form errors identified, described in text, and include correction suggestion
  • Native HTML elements used in preference to ARIA
  • Custom ARIA components implement keyboard patterns from ARIA APG
  • Lighthouse a11y score ≥ 90
  • axe DevTools scan returns 0 violations
  • Manual keyboard-only test completed
  • Screen reader test (VoiceOver or NVDA) completed on primary user journeys

About the Editorial Team This analysis was conducted by our independent research desk. We utilize verified market data and specialized methodology to provide objective, expert insights. Our strict editorial policy ensures no undue influence from sponsors or external parties.

Lucky Graphics Archive

This archived draft is retained for editorial review and is not part of the site’s indexed publication set.

Tags
#Accessibility#WCAG 2.2#A11y#Inclusive Design#Web Standards

Found this helpful?

Share this guide with your network

Continue Reading

Ready to Put This Into Practice?

Browse our curated collection of design assets to find the perfect resources for your next project.

Explore Assets