WCAG 2.2 Developer Guide

A comprehensive, practical guide to Web Content Accessibility Guidelines (WCAG) 2.2. Written for developers who want to build accessible web applications.

Understanding WCAG Conformance Levels

Level A
Essential - Minimum level of conformance. Addresses the most basic web accessibility features.
Level AA
Recommended - Industry standard. Required by most laws and regulations (ADA, Section 508, etc.).
Level AAA
Enhanced - Highest level. Provides the best accessibility but may not be achievable for all content.

Perceivable

1.1.1Level A

Non-text Content

What it means:

All non-text content (images, icons, charts) must have text alternatives.

For developers:

Always provide meaningful alt text for images. For decorative images, use empty alt attribute.

Code example:
❌ Don't do this:
<img src="chart.png">
✅ Do this instead:
<img src="chart.png" alt="Sales revenue increased 45% in Q4 2024">
Key points:
  • Use descriptive alt text that conveys the same information
  • Decorative images should have alt=""
  • Complex images (charts, diagrams) need longer descriptions
  • Icon buttons need accessible labels via aria-label
1.3.1Level A

Info and Relationships

What it means:

Information, structure, and relationships must be programmatically determinable.

For developers:

Use semantic HTML elements to convey structure and meaning.

Code example:
❌ Don't do this:
<div class="heading">Page Title</div>
<div class="list">
  <div>Item 1</div>
  <div>Item 2</div>
</div>
✅ Do this instead:
<h1>Page Title</h1>
<ul>
  <li>Item 1</li>
  <li>Item 2</li>
</ul>
Key points:
  • Use proper heading hierarchy (h1, h2, h3)
  • Use <ul>, <ol> for lists, not divs
  • Use <table> with proper headers for tabular data
  • Label form inputs with <label> or aria-label
1.3.4Level AA

Orientation

What it means:

Content must not be restricted to a single display orientation (portrait/landscape).

For developers:

Don't lock orientation unless essential. Support both portrait and landscape modes.

Key points:
  • Avoid CSS that forces specific orientation
  • Test responsive design in both orientations
  • Only lock orientation when absolutely necessary (e.g., piano app)
1.3.5Level AA

Identify Input Purpose

What it means:

Input fields that collect user information must identify their purpose programmatically.

For developers:

Use HTML5 autocomplete attributes to identify input purpose.

Code example:
❌ Don't do this:
<input type="text" name="email">
✅ Do this instead:
<input type="email" name="email" autocomplete="email">
Key points:
  • Use autocomplete="email" for email inputs
  • Use autocomplete="name" for name fields
  • Use autocomplete="tel" for phone numbers
  • Helps browsers auto-fill and assistive tech understand context
1.4.3Level AA

Contrast (Minimum)

What it means:

Text must have a contrast ratio of at least 4.5:1 (3:1 for large text).

For developers:

Use color contrast checkers during design. Test with browser dev tools.

Code example:
❌ Don't do this:
/* Light gray text on white */
color: #CCCCCC;
background: #FFFFFF;
✅ Do this instead:
/* Dark gray text on white */
color: #595959;
background: #FFFFFF;
Key points:
  • Normal text needs 4.5:1 contrast ratio
  • Large text (18pt+ or 14pt+ bold) needs 3:1
  • Test with tools like Chrome DevTools or WebAIM contrast checker
  • Don't rely on color alone to convey information
1.4.10Level AA

Reflow

What it means:

Content must reflow without horizontal scrolling at 320px width (400% zoom).

For developers:

Build responsive layouts that work at 320px width. Test by zooming to 400%.

Key points:
  • Avoid fixed widths in pixels
  • Use responsive units (rem, em, %)
  • Test at 400% zoom in browser
  • Allow content to reflow vertically
1.4.11Level AA

Non-text Contrast

What it means:

UI components and graphical objects must have 3:1 contrast ratio.

For developers:

Ensure buttons, form inputs, icons, and focus indicators have sufficient contrast.

Key points:
  • Button borders need 3:1 contrast
  • Form input borders need 3:1 contrast
  • Focus indicators must be visible (3:1 contrast)
  • Chart elements need distinguishable colors
1.4.12Level AA

Text Spacing

What it means:

Content must not break when users adjust text spacing (line height, paragraph spacing, etc.).

For developers:

Test with increased text spacing. Avoid overflow: hidden on text containers.

Key points:
  • Test with 1.5x line height
  • Test with 2x paragraph spacing
  • Avoid fixed heights on text containers
  • Content should reflow, not clip
1.4.13Level AA

Content on Hover or Focus

What it means:

Tooltips and popovers triggered by hover/focus must be dismissible, hoverable, and persistent.

For developers:

Ensure tooltips can be dismissed with Esc key, can be hovered over, and don't disappear automatically.

Key points:
  • Tooltip must not disappear when user hovers over it
  • Provide Esc key to dismiss
  • Don't auto-hide unless user moves pointer away
  • Ensure keyboard users can trigger and dismiss

Operable

2.1.1Level A

Keyboard

What it means:

All functionality must be available via keyboard.

For developers:

Test your entire app using only keyboard (Tab, Enter, Space, Arrow keys).

Code example:
❌ Don't do this:
<div onclick="submitForm()">Submit</div>
✅ Do this instead:
<button type="submit">Submit</button>
Key points:
  • Use semantic HTML (button, a, input)
  • Don't use div/span for interactive elements
  • Test with Tab key for navigation
  • Ensure Enter/Space activates buttons
2.1.2Level A

No Keyboard Trap

What it means:

Users must be able to navigate away from any component using keyboard.

For developers:

Ensure modals, custom widgets don't trap keyboard focus. Tab should cycle through, Esc should exit.

Key points:
  • Modal dialogs should trap focus within themselves
  • But Esc key should close modal and return focus
  • Custom widgets must allow Tab to move focus out
  • Test keyboard navigation thoroughly
2.1.4Level A

Character Key Shortcuts

What it means:

Single character keyboard shortcuts must be remappable or can be turned off.

For developers:

If using single-key shortcuts (e.g., "S" for save), provide a way to disable or remap them.

Key points:
  • Avoid single-character shortcuts (conflict with screen readers)
  • Use Ctrl/Cmd + key instead
  • If necessary, allow users to turn off shortcuts
  • Provide remapping in settings
2.2.1Level A

Timing Adjustable

What it means:

Users must be able to extend, adjust, or turn off time limits.

For developers:

Provide options to extend timeouts, or warn users before timeout occurs.

Key points:
  • Session timeouts should warn users beforehand
  • Provide "Extend session" option
  • Auto-save form data to prevent loss
  • Don't use arbitrary time limits
2.2.2Level A

Pause, Stop, Hide

What it means:

Moving, blinking, or auto-updating content must have pause/stop controls.

For developers:

Carousels, animations, auto-updating content need pause buttons.

Code example:
❌ Don't do this:
// Auto-play carousel with no controls
setInterval(nextSlide, 3000)
✅ Do this instead:
// Carousel with pause button
<button onClick={pauseCarousel}>Pause</button>
Key points:
  • Provide pause button for carousels
  • Don't auto-play videos without controls
  • Auto-updating content (news ticker) needs pause
  • Avoid infinite auto-advance
2.3.1Level A

Three Flashes or Below Threshold

What it means:

Content must not flash more than 3 times per second.

For developers:

Avoid flashing animations, strobe effects. Can trigger seizures.

Key points:
  • Never use rapid flashing effects
  • Avoid animated GIFs with quick flashing
  • Test animations frame-by-frame
  • Large flashing areas are especially dangerous
2.4.1Level A

Bypass Blocks

What it means:

Provide a way to skip repeated navigation (skip links).

For developers:

Add a "Skip to main content" link at the top of every page.

Code example:
❌ Don't do this:
// No skip link
✅ Do this instead:
<a href="#main" class="skip-link">Skip to main content</a>
<main id="main">...</main>
Key points:
  • First focusable element should be skip link
  • Link should jump to main content
  • Can be visually hidden but keyboard accessible
  • Helps keyboard users skip navigation
2.4.2Level A

Page Titled

What it means:

Every page must have a descriptive title.

For developers:

Use unique, descriptive page titles. Format: "Page Name - Site Name".

Code example:
❌ Don't do this:
<title>Page</title>
✅ Do this instead:
<title>Account Settings - Blyxo</title>
Key points:
  • Title should describe page content
  • Make titles unique across pages
  • Put most specific info first
  • Update title on SPA route changes
2.4.3Level A

Focus Order

What it means:

Keyboard focus order must be logical and intuitive.

For developers:

Tab order should follow visual layout. Avoid positive tabindex values.

Key points:
  • Never use tabindex > 0
  • Use semantic HTML for natural order
  • Test tab order matches visual order
  • Use tabindex="-1" to remove from tab order
2.4.4Level A

Link Purpose (In Context)

What it means:

Link purpose must be clear from link text or context.

For developers:

Avoid "Click here" or "Read more". Use descriptive link text.

Code example:
❌ Don't do this:
<a href="/report.pdf">Click here</a>
✅ Do this instead:
<a href="/report.pdf">Download Q4 2024 Accessibility Report (PDF, 2.3MB)</a>
Key points:
  • Link text should describe destination
  • Include file type and size for downloads
  • Avoid "Click here", "Learn more"
  • Screen readers often list links out of context
2.4.5Level AA

Multiple Ways

What it means:

Provide multiple ways to find pages (navigation, search, sitemap).

For developers:

Include navigation menu, search functionality, and optionally a sitemap.

Key points:
  • Main navigation should be consistent
  • Provide search functionality
  • Consider breadcrumbs for deep sites
  • Sitemap can help with discoverability
2.4.6Level AA

Headings and Labels

What it means:

Headings and labels must be descriptive.

For developers:

Use clear, descriptive headings and form labels.

Code example:
❌ Don't do this:
<h2>Details</h2>
<label>Field 1</label>
✅ Do this instead:
<h2>Account Settings</h2>
<label>Email Address</label>
Key points:
  • Headings should describe section content
  • Form labels should clearly identify purpose
  • Avoid vague labels like "Input"
  • Be specific and descriptive
2.4.7Level AA

Focus Visible

What it means:

Keyboard focus must be clearly visible.

For developers:

Don't remove focus outlines. Style them to be visible against all backgrounds.

Code example:
❌ Don't do this:
/* Never do this! */
*:focus { outline: none; }
✅ Do this instead:
*:focus {
  outline: 2px solid #0066CC;
  outline-offset: 2px;
}
Key points:
  • Never use outline: none without replacement
  • Focus indicator needs 3:1 contrast
  • Make focus visible on all backgrounds
  • Test with keyboard navigation
2.4.11Level AA

Focus Not Obscured (Minimum)

What it means:

When an element receives focus, it must not be entirely hidden by other content.

For developers:

Ensure sticky headers, footers, or modals don't completely hide focused elements.

Key points:
  • Scroll focused element into view
  • Account for sticky headers when scrolling
  • At least part of focused element must be visible
  • Use scrollIntoView() with block: "nearest"
2.5.1Level A

Pointer Gestures

What it means:

All multipoint or path-based gestures must have single-pointer alternative.

For developers:

Don't require pinch-to-zoom, two-finger swipe, etc. Provide buttons instead.

Key points:
  • Provide + / - buttons instead of pinch-to-zoom
  • Single tap/click should work for all functionality
  • Avoid requiring drag-and-drop (provide alternative)
  • Path-based gestures need alternatives
2.5.2Level A

Pointer Cancellation

What it means:

Actions should complete on pointer up event, not down.

For developers:

Use onClick, not onMouseDown. Allows users to cancel by moving pointer away.

Key points:
  • Use onClick instead of onMouseDown
  • Allows users to cancel accidental clicks
  • Exception: down-event needed (e.g., piano keys)
  • Provide undo for critical actions
2.5.3Level A

Label in Name

What it means:

Accessible name must include visible label text.

For developers:

If button shows "Submit", accessible name should include "Submit".

Code example:
❌ Don't do this:
<button aria-label="Send form">Submit</button>
✅ Do this instead:
<button>Submit</button>
<!-- or -->
<button aria-label="Submit form">Submit</button>
Key points:
  • Visible text should match or be included in accessible name
  • Helps voice control users ("Click Submit")
  • Don't override with completely different aria-label
  • Accessible name can add context but must include visible text
2.5.4Level A

Motion Actuation

What it means:

Functionality triggered by device motion must have UI alternative.

For developers:

If using shake-to-undo or tilt controls, provide button alternatives.

Key points:
  • Don't rely solely on device motion
  • Provide button alternative to shake/tilt
  • Allow users to disable motion activation
  • Motion can be difficult for users with disabilities
2.5.7Level AA

Dragging Movements

What it means:

Dragging interactions must have single-pointer alternative.

For developers:

Provide buttons/inputs as alternative to drag-and-drop, sliders, etc.

Key points:
  • Sliders should have input field alternative
  • Drag-and-drop should have cut/paste buttons
  • Provide arrow buttons for reordering
  • Some users can't perform dragging
2.5.8Level AA

Target Size (Minimum)

What it means:

Interactive elements must be at least 24x24 CSS pixels.

For developers:

Make buttons, links, and touch targets at least 24x24px. Ideally 44x44px.

Code example:
❌ Don't do this:
button { width: 16px; height: 16px; }
✅ Do this instead:
button {
  min-width: 24px;
  min-height: 24px;
  padding: 8px;
}
Key points:
  • Minimum: 24x24px for AA compliance
  • Recommended: 44x44px for better usability
  • Include padding in calculations
  • Exceptions: inline links in sentences

Understandable

3.1.1Level A

Language of Page

What it means:

Default language of page must be programmatically determined.

For developers:

Set lang attribute on html element.

Code example:
❌ Don't do this:
<html>
✅ Do this instead:
<html lang="en">
Key points:
  • Always set lang on <html>
  • Use correct language code (en, es, fr)
  • Helps screen readers pronounce correctly
  • Required for translation tools
3.1.2Level AA

Language of Parts

What it means:

Language changes within content must be marked.

For developers:

When mixing languages, mark foreign text with lang attribute.

Code example:
❌ Don't do this:
<p>The French word bonjour means hello.</p>
✅ Do this instead:
<p>The French word <span lang="fr">bonjour</span> means hello.</p>
Key points:
  • Mark foreign phrases with lang attribute
  • Helps screen readers switch pronunciation
  • Apply to spans, paragraphs, or other elements
  • Not needed for proper names or universal terms
3.2.1Level A

On Focus

What it means:

Receiving focus must not trigger unexpected context changes.

For developers:

Don't automatically submit forms, navigate, or open modals on focus.

Key points:
  • Focus should not auto-submit forms
  • Don't auto-open modals on focus
  • Don't navigate to new page on focus
  • User should initiate actions (click, Enter)
3.2.2Level A

On Input

What it means:

Changing input values must not cause unexpected context changes.

For developers:

Don't auto-submit when user types or selects. Wait for explicit submit action.

Key points:
  • Don't auto-submit on select change
  • Don't navigate on dropdown selection
  • Provide explicit submit button
  • Auto-save is OK if it doesn't change context
3.2.3Level AA

Consistent Navigation

What it means:

Navigation must be consistent across pages.

For developers:

Keep navigation menu in same location with same items across site.

Key points:
  • Navigation order should be consistent
  • Don't rearrange menu items between pages
  • Keep navigation in same location
  • Helps users build mental model
3.2.4Level AA

Consistent Identification

What it means:

Components with same functionality must be identified consistently.

For developers:

Use same icon, label, and text for same actions across site.

Key points:
  • Save button should always look/say the same
  • Search icon should be consistent
  • Don't call it "Search" on one page, "Find" on another
  • Consistency aids recognition and learning
3.2.6Level A

Consistent Help

What it means:

Help mechanisms must be in consistent locations.

For developers:

If you provide help links/chat/contact, keep them in same place on every page.

Key points:
  • Help link should be in same location
  • Chat widget in consistent corner
  • Contact info in same place (e.g., footer)
  • Relative order should stay the same
3.3.1Level A

Error Identification

What it means:

Form errors must be clearly identified and described.

For developers:

Show clear error messages next to fields. Use aria-invalid and aria-describedby.

Code example:
❌ Don't do this:
<input type="email" class="error">
✅ Do this instead:
<input type="email" aria-invalid="true" aria-describedby="email-error">
<div id="email-error" role="alert">Please enter a valid email address</div>
Key points:
  • Use aria-invalid="true" on error fields
  • Link to error message with aria-describedby
  • Use role="alert" for error messages
  • Describe what's wrong and how to fix it
3.3.2Level A

Labels or Instructions

What it means:

Form inputs must have clear labels or instructions.

For developers:

Every input needs a visible label. Provide format requirements and constraints.

Code example:
❌ Don't do this:
<input type="text" placeholder="Email">
✅ Do this instead:
<label for="email">Email Address</label>
<input id="email" type="email" required>
Key points:
  • Use <label> element for every input
  • Don't rely on placeholder alone
  • Explain format requirements (e.g., "MM/DD/YYYY")
  • Mark required fields clearly
3.3.3Level AA

Error Suggestion

What it means:

Error messages should suggest how to fix the error.

For developers:

Don't just say "Invalid input". Explain what's wrong and how to correct it.

Code example:
❌ Don't do this:
"Error: Invalid date"
✅ Do this instead:
"Please enter date in MM/DD/YYYY format (e.g., 12/31/2024)"
Key points:
  • Explain what's wrong
  • Show correct format or example
  • Suggest corrections when possible
  • Be specific and helpful
3.3.4Level AA

Error Prevention (Legal, Financial, Data)

What it means:

Critical actions must be reversible, verified, or confirmed.

For developers:

For legal/financial/data actions, provide confirmation step or allow undo.

Key points:
  • Show confirmation dialog before submitting
  • Allow review and edit before final submit
  • Provide undo functionality
  • Especially important for purchases, agreements, data deletion
3.3.7Level A

Redundant Entry

What it means:

Don't require users to enter the same information twice in one process.

For developers:

Auto-fill previously entered data. Don't make users re-enter shipping address for billing.

Key points:
  • Pre-populate fields with known data
  • Provide "Same as shipping" checkbox
  • Use autocomplete attributes
  • Don't make users re-enter what you already know
3.3.8Level AA

Accessible Authentication (Minimum)

What it means:

Authentication must not rely solely on cognitive function tests.

For developers:

Don't require users to solve puzzles or transcribe distorted text. Use alternative methods.

Key points:
  • Avoid CAPTCHAs that require solving puzzles
  • Provide alternative auth methods (magic link, passkey)
  • Allow password managers to work
  • Don't require remembering complex patterns

Robust

4.1.1Level A

Parsing

What it means:

HTML must be well-formed (deprecated in WCAG 2.2 - browsers now handle this).

For developers:

Write valid HTML. Use linters to catch syntax errors.

Key points:
  • Close all tags properly
  • Don't duplicate IDs
  • Use valid HTML syntax
  • This criterion is deprecated but still good practice
4.1.2Level A

Name, Role, Value

What it means:

All UI components must have programmatically determinable name, role, and value.

For developers:

Use semantic HTML or ARIA to expose component information to assistive tech.

Code example:
❌ Don't do this:
<div onclick="toggle()">Toggle</div>
✅ Do this instead:
<button type="button" aria-pressed="false">Toggle</button>
Key points:
  • Use semantic HTML (button, checkbox, etc.)
  • Add ARIA roles for custom components
  • Ensure state changes are announced (aria-pressed, aria-expanded)
  • Test with screen reader
4.1.3Level AA

Status Messages

What it means:

Status messages must be announced to screen readers without receiving focus.

For developers:

Use role="status" or role="alert" for dynamic content updates.

Code example:
❌ Don't do this:
<div id="message">Item added to cart</div>
✅ Do this instead:
<div role="status" aria-live="polite">Item added to cart</div>
Key points:
  • Use role="status" for non-urgent updates
  • Use role="alert" for important/urgent messages
  • Don't move focus to status messages
  • Screen reader will announce automatically

Need Help Testing Your Site?

Blyxo automatically tests your website against all WCAG 2.2 guidelines and provides detailed, actionable reports with code-level remediation guidance.

Request a Demo