- by Wouter Nordsiek
- 0 Comments
- Guide
- 22 September 2025
Β
WCAG Accessibility Quick Reference Guide
Based on 2024 – march 2026 NGI project audits – Comprehensive reference to implement WCAG 2.2 Level AA compliance in web applications and mobile apps
π Table of Contents
π Getting Started
π― Top Priority Issues (Most Critical)
- 1. Keyboard Navigation (2,410 violations)
- 2. Color Contrast Issues (1,431 violations)
- 3. Form Accessibility (487 violations)
ποΈ Foundation Issues (Sections 4-10)
- 4. Information and Relationships
- 5. Skip Links and Navigation
- 6. Focus Visibility
- 7. Headings and Labels
- 8. Use of Color
- 9. Link Purpose
- 10. Reflow and Responsive Design
π§ Advanced Implementation (Sections 11-15)
- 11. Focus Order and Navigation
- 12. Image Alt Text
- 13. ARIA Implementation
- 14. Form Validation and Error Identification
- 15. Page Language and Accessibility Name
π§ͺ Testing & Tools
π About This Reference
This document is a quick reference of the most common WCAG errors found across 78 real projects. Each issue includes a brief overview and code snippets.
For detailed implementation with interactive demos, use these dedicated component guides:
- Accessible Dropdown Menus – Complete guide with keyboard navigation, ARIA, and screen reader support
- Keyboard Navigation – Tab order, focus trapping, skip links, and arrow key patterns (2,410 violations)
- Color Contrast – Contrast ratios, accessible palettes, and a live contrast checker (1,431 violations)
- Coming soon: Form Labels – Label association, ARIA naming, icon buttons, and fieldsets (487 violations)
- Coming soon: Form Validation – Error identification, ARIA live regions, and real-time feedback (45 violations)
Executive Summary
Analysis Overview: Based on comprehensive accessibility audits of 78 NGI projects conducted in 2024β march 2026, with a total of 5,812 documented WCAG violations. This data represents the most common accessibility issues found across tested web applications, mobile apps, and desktop software.
π Note on Document Structure: While the table below shows issues ranked by frequency, the guide sections (1-15) are organized pedagogically – from fundamental concepts to advanced implementation. This helps developers build accessibility knowledge systematically, starting with the highest-impact basics.
Top 5 Most Critical Issues
| Rank | Issue Type | Total Violations | Primary Affected Areas |
|---|---|---|---|
| 1 | Keyboard Navigation (2.1.1) | 2,410 | Mobile apps, XR/VR, complex UI components (77/78 projects) |
| 2 | Color Contrast (1.4.3) | 1,431 | Links, buttons, focus indicators, modern UI (75/78 projects) |
| 3 | Image Alt Text (1.1.1) | 301 | Missing alt text, decorative images, icons (39/78 projects) |
| 4 | Form Labels (3.3.2) | 238 | Labels, input fields, form instructions (44/78 projects) |
| 5 | Headings and Labels (2.4.6) | 228 | Heading structure, descriptive labels (27/78 projects) |
Key Insights
- Keyboard Navigation is #1 Issue: 2,410 violations across 77 of 78 projects β by far the most prevalent accessibility barrier, especially in mobile apps and XR/VR interfaces
- Color Contrast remains persistent: 1,431 violations across 75 of 78 projects, confirming this fundamental issue affects nearly every project regardless of type
- Keyboard + Contrast = 70% of all issues: These two categories alone account for 3,841 of 5,812 total violations β fixing them has the biggest impact
- Image Alt Text widespread: 301 violations in half of all projects β a quick win that is often overlooked
- Form and label issues underestimated: 487 combined form-related violations (labels, ARIA naming, validation) across 44 projects
- Advanced projects struggle with ARIA: Complex implementations often contain errors, suggesting need for better ARIA training
1. Keyboard Navigation – 2,410 Violations
WCAG Reference: 2.1.1 Keyboard – Level A
The most common accessibility issue found, particularly affecting mobile apps and XR/VR applications that often lack proper keyboard alternatives.
Common Problems
- Can’t navigate the entire site using only Tab, Shift+Tab, Enter, Space, and arrow keys
- Dropdown menus not accessible via keyboard
- Modals don’t trap focus properly
- Custom components (sliders, carousels) lack keyboard support
- Missing skip links for main content
βΌ
Essential Code Patterns
<!-- Basic keyboard accessible dropdown -->
<button aria-expanded="false" aria-haspopup="menu">Menu</button>
<ul role="menu" hidden>
<li role="none"><a href="#" role="menuitem">Option 1</a></li>
</ul>
<!-- Custom interactive element -->
<div tabindex="0" role="slider"
aria-valuenow="50" aria-valuemin="0" aria-valuemax="100"
onkeydown="handleArrowKeys(event)">
</div>
<!-- Skip links (first elements on page) -->
<a href="#main-content" class="skip-link">Skip to main content</a>
<a href="#navigation" class="skip-link">Skip to navigation</a>π Interactive Demos: Part 1: Keyboard Navigation – Working dropdown, slider and modal demos
Quick Test: Unplug your mouse β Use only Tab, Enter, Space, Arrow keys β Verify all functionality works
2. Color Contrast Issues – 1,431 Violations
WCAG Reference: 1.4.3 Contrast (Minimum) – Level AA
A persistent and widespread issue, affecting everything from simple links to complex modern UI patterns including dark themes, gradients, and subtle interactive states.
Common Problems
- Links that don’t meet the minimum 4.5:1 contrast ratio requirement
- Focus indicators with insufficient contrast against backgrounds
- Subtle hover states and button outlines that blend with backgrounds
- Modern minimal design with insufficient contrast
- Dark themes with inadequate light text contrast
- Gradient backgrounds affecting text readability
βΌ
Essential Code Patterns
/* Ensure minimum 4.5:1 contrast for normal text */
.link-text {
color: #0066cc; /* 4.51:1 on white background */
}
/* Large text: 18pt (24px) and larger, or 14pt (18.67px) and larger when bold */
.large-text {
color: #767676; /* 4.54:1 on white background - meets AA large text */
font-size: 24px; /* 18pt = 24px minimum for large text */
}
/* Fix subtle button outlines that blend with background */
.button {
background: #0066cc;
color: white;
border: 2px solid #004499; /* Darker border for definition */
}
.button:hover {
background: #0052a3; /* Darker on hover, still 4.5:1+ contrast */
border: 2px solid #003366;
}
.button:focus {
outline: 3px solid #ff6600; /* High contrast focus indicator */
outline-offset: 2px;
}
/* Dark theme considerations */
.dark-theme {
background: #1a1a1a;
color: #ffffff; /* 15.3:1 contrast ratio */
}
/* Ensure text over gradients has sufficient contrast */
.gradient-banner {
background: linear-gradient(135deg, #0066cc, #004499);
color: white; /* Test against darkest gradient color */
text-shadow: 1px 1px 2px rgba(0,0,0,0.8); /* Backup for edge cases */
}Testing Tools
- WebAIM Contrast Checker
- Colour Contrast Analyser
- Browser DevTools accessibility features
π Interactive Demos: Part 1: Color Contrast – Visual comparison demos and testing tools
Quick Test: Use a contrast checker β Verify all text meets 4.5:1 (normal) or 3:1 (large text) β Check focus indicators
3. Form Accessibility – 487 Violations
WCAG Reference: 4.1.2 Name, Role, Value – Level A
Common Problems
- Calendar and notification buttons without proper labels
- Login and register elements missing labels
- iframe elements without accessible names
- Form validation errors shown without proper identification
- Submit buttons with only icons and no text alternatives
- Toggle buttons missing state information (pressed/unpressed)
βΌ
Essential Code Patterns
<!-- Proper button labeling -->
<button aria-label="Open calendar">
<svg aria-hidden="true"><!-- calendar icon --></svg>
</button>
<!-- Form labels -->
<label for="username">Username (required)</label>
<input type="text" id="username" name="username" required aria-describedby="username-help">
<div id="username-help">Enter your email address</div>
<!-- iframe accessibility -->
<iframe src="map.html" title="Interactive campus map"></iframe>
<!-- Form with proper error handling -->
<form novalidate>
<input type="email"
id="email"
required
aria-describedby="email-error"
aria-invalid="false">
<div id="email-error" role="alert"></div>
</form>π Interactive Demos: Part 1: Form Accessibility – Working validation demos
Quick Test: Use screen reader β Navigate through form β Verify all fields and buttons are clearly announced
4. Information and Relationships – 167 Violations
WCAG Reference: 1.3.1 Info and Relationships – Level A
Common Problems
- H1 and H5 headings present, but intermediate heading levels (H2-H4) are skipped
- Improper semantic structure breaking screen reader navigation
- Content that looks like headings but isn’t marked up as headings
- Missing landmark regions (header, nav, main, aside, footer)
βΌ
Essential Code Patterns
<!-- Proper heading hierarchy -->
<h1>Main Page Title</h1>
<h2>Section Title</h2>
<h3>Subsection Title</h3>
<h4>Sub-subsection Title</h4>
<!-- Semantic landmarks -->
<header>
<nav aria-label="Main navigation">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
</header>
<main>
<article>
<h1>Article Title</h1>
<section>
<h2>Section Title</h2>
</section>
</article>
</main>
<aside aria-label="Related articles">
<h2>Related Content</h2>
</aside>
<footer>
<p>© 2025 Company Name</p>
</footer>π Interactive Demos: Part 3: Information and Relationships – Heading hierarchy demos
Quick Test: Use browser DevTools β Check document outline β Verify logical heading structure
5. Skip Links and Navigation – 179 Violations
WCAG Reference: 2.4.1 Bypass Blocks – Level A
Common Problems
- No skip links provided on pages
- Skip links that don’t work or lead to wrong content
- Skip links only visible on focus but poorly positioned
- Missing skip links for repetitive content blocks
βΌ
Essential Code Patterns
<!-- Skip links should be first focusable elements -->
<a href="#main-content" class="skip-link">Skip to main content</a>
<a href="#navigation" class="skip-link">Skip to navigation</a>
<nav id="navigation" aria-label="Main navigation">
<!-- Navigation items -->
</nav>
<main id="main-content" tabindex="-1">
<h1>Main Content Starts Here</h1>
<!-- Main page content -->
</main>
<!-- Skip links CSS -->
<style>
.skip-link {
position: absolute;
top: -40px;
left: 6px;
background: #000;
color: #fff;
padding: 8px 16px;
text-decoration: none;
border-radius: 0 0 4px 4px;
z-index: 1000;
transition: top 0.3s ease;
}
.skip-link:focus {
top: 6px; /* Slide down when focused */
}
</style>π Interactive Demos: Part 3: Skip Links – Working skip link demo
Quick Test: Press Tab on page load β Skip link appears β Press Enter β Focus jumps to main content
6. Focus Visibility – 103 Violations
WCAG Reference: 2.4.7 Focus Visible – Level AA
Common Problems
- Interactive elements without visible focus indicators
- Focus indicators with insufficient contrast against backgrounds
- CSS that removes all focus indicators (outline: none)
- Focus indicators that disappear behind other elements
βΌ
Essential Code Patterns
/* Custom focus indicators */
.button:focus {
outline: 3px solid #ff6600;
outline-offset: 2px;
}
/* For elements where outline doesn't work well */
.card:focus {
box-shadow: 0 0 0 3px #ff6600;
}
/* For dark backgrounds */
.dark-theme .button:focus {
outline: 3px solid #ffcc00; /* Bright yellow on dark */
outline-offset: 2px;
}
/* NEVER remove focus indicators entirely */
/* DON'T do this: *:focus { outline: none; } */π Interactive Demos: Part 3: Focus Visibility – Good vs bad focus demos
Quick Test: Use Tab key β Navigate through all interactive elements β Verify clear focus indicators
7. Headings and Labels – 228 Violations
WCAG Reference: 2.4.6 Headings and Labels – Level AA
Common Problems
- Generic headings like “Welcome” that don’t describe content
- Form labels that don’t clearly explain what’s expected
- Links with generic text like “click here” or “read more”
- Buttons labeled only with icons
βΌ
Essential Code Patterns
<!-- Descriptive headings -->
<h1>User Dashboard - Account Overview</h1>
<h2>Recent Transaction History</h2>
<h2>Account Security Settings</h2>
<!-- Descriptive form labels -->
<label for="search-products">Search products by name or category</label>
<input type="search" id="search-products" placeholder="e.g., wireless headphones">
<!-- Group related fields -->
<fieldset>
<legend>Shipping Address</legend>
<label for="street">Street Address (required)</label>
<input type="text" id="street" name="street" required>
<label for="city">City (required)</label>
<input type="text" id="city" name="city" required>
</fieldset>π Interactive Demos: Part 3: Headings and Labels – Descriptive examples
Quick Test: Read headings out of context β Do they make sense? β Check form labels are clear
8. Use of Color – 20 Violations
WCAG Reference: 1.4.1 Use of Color – Level A
Common Problems
- Links only indicated by color without other visual cues
- Form validation errors shown only in red color
- Status indicators using only color (green=success, red=error)
- Charts and graphs relying solely on color coding
βΌ
Essential Code Patterns
<!-- Links with multiple indicators -->
<a href="/download" class="download-link">
Download Report
<svg aria-hidden="true"><!-- download icon --></svg>
</a>
<!-- Error messages with icons and text -->
<div class="error-message" role="alert">
<svg aria-hidden="true"><!-- error icon --></svg>
<strong>Error:</strong> Email address is required
</div>
<!-- Status indicators with text + icons + color -->
<span class="status-success">
<svg aria-hidden="true"><!-- checkmark icon --></svg>
Success
</span>
<span class="status-warning">
<svg aria-hidden="true"><!-- warning icon --></svg>
Warning
</span>
<span class="status-error">
<svg aria-hidden="true"><!-- X icon --></svg>
Error
</span>π Interactive Demos: Part 3: Use of Color – Color-blind comparison demos
Quick Test: Use grayscale filter β Check all information is still clear β Test with color blindness simulator
9. Link Purpose – 59 Violations
WCAG Reference: 2.4.4 Link Purpose (In Context) – Level A
Common Problems
- Multiple “read more” or “click here” links on the same page
- Links that don’t describe their destination
- Download links without file type or size information
- Links that open in new windows without warning
βΌ
Essential Code Patterns
<!-- Descriptive link text -->
<!-- BAD: <a href="/report.pdf">Click here</a> -->
<!-- GOOD -->
<a href="/report.pdf">Download accessibility report (PDF, 2.3MB)</a>
<a href="/wcag-guide">Read more about WCAG implementation</a>
<!-- External links with indicators -->
<a href="https://w3.org/WAI" target="_blank" rel="noopener">
Web Accessibility Initiative
<span class="sr-only">(opens in new window)</span>
<svg aria-hidden="true" class="external-icon">
<!-- external link icon -->
</svg>
</a>
<!-- Context-specific "read more" links -->
<article>
<h3>Product Review</h3>
<p>Our latest smartphone review...</p>
<a href="/review/smartphone-2025">Read full smartphone review</a>
</article>π Interactive Demos: Part 3: Link Purpose – Descriptive link examples
Quick Test: Read link text alone β Does it make sense out of context? β Check external link warnings
10. Reflow and Responsive Design – 149 Violations
WCAG Reference: 1.4.10 Reflow – Level AA
Common Problems
- Fixed-width layouts that break when zoomed
- Text that overlaps or disappears at high zoom levels
- Horizontal scrolling required at 400% zoom
- Content that becomes unusable on small screens
βΌ
Essential Code Patterns
/* Responsive design without horizontal scrolling */
.container {
max-width: 1200px;
width: 100%;
margin: 0 auto;
padding: 0 20px;
}
/* Flexible layouts */
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
}
/* Text that scales properly */
body {
font-size: 1rem; /* Use rem units */
line-height: 1.5;
}
/* Responsive images */
img {
max-width: 100%;
height: auto;
}
/* Avoid fixed widths */
/* BAD: .sidebar { width: 300px; } */
/* Use flexible widths */
.sidebar {
width: 100%;
max-width: 300px;
}π Interactive Demos: Part 3: Reflow and Responsive – Zoom testing demo
Quick Test: Zoom to 400% β Verify no horizontal scrolling β Check all content remains accessible
11. Focus Order and Navigation – 122 Violations
WCAG Reference: 2.4.3 Focus Order – Level A
Common Problems
- Sidebars that interrupt main content flow
- Modal dialogs that don’t trap focus properly
- Dynamic content insertion breaking tab order
- Skip links that don’t work correctly
- Illogical tab sequences that confuse keyboard users
βΌ
Essential Code Patterns
<!-- Use tabindex to control focus order when needed -->
<main id="main-content">
<h1 tabindex="-1">Page Title</h1> <!-- Can receive focus programmatically -->
<nav aria-label="Page contents">
<a href="#section1">Section 1</a>
<a href="#section2">Section 2</a>
</nav>
<section id="section1" tabindex="-1">
<h2>Section 1</h2>
<!-- Content -->
</section>
</main>
<!-- Modal focus trap JavaScript -->
<script>
function openModal(modalId) {
const modal = document.getElementById(modalId);
const focusableElements = modal.querySelectorAll(
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
);
const firstElement = focusableElements[0];
const lastElement = focusableElements[focusableElements.length - 1];
// Focus first element
firstElement.focus();
// Trap focus within modal
modal.addEventListener('keydown', function(e) {
if (e.key === 'Tab') {
if (e.shiftKey) {
if (document.activeElement === firstElement) {
lastElement.focus();
e.preventDefault();
}
} else {
if (document.activeElement === lastElement) {
firstElement.focus();
e.preventDefault();
}
}
}
});
}
</script>π Interactive Demos: Part 2: Focus Order and Navigation – Modal focus trap demos
Quick Test: Open modal β Press Tab β Verify focus stays within modal β Press Escape β Focus returns to trigger
12. Image Alt Text – 301 Violations
WCAG Reference: 1.1.1 Non-text Content – Level A
Common Problems
- Images don’t have alternative text or are not descriptive
- Icons lack alternative text descriptions
- Decorative images with unnecessary alt text
- Complex images without proper descriptions
- Generic alt text like “image” or “photo”
βΌ
Essential Code Patterns
<!-- Informative images -->
<img src="chart.png" alt="Sales increased 25% from January to March 2025">
<!-- Decorative images -->
<img src="decoration.png" alt="" role="presentation">
<!-- Complex images with detailed description -->
<img src="process-diagram.png" alt="User registration process" aria-describedby="process-desc">
<div id="process-desc">
The diagram shows 4 steps: 1) User fills form, 2) Email verification,
3) Admin approval, 4) Account activated
</div>
<!-- Icons in buttons -->
<button>
<svg aria-hidden="true"><!-- save icon --></svg>
Save Document
</button>
<!-- Icon-only buttons -->
<button aria-label="Close dialog">
<svg aria-hidden="true"><!-- close icon --></svg>
</button>π Interactive Demos: Part 2: Image Alt Text – Good vs bad alt text examples
Quick Test: Turn off images β Use screen reader β Verify all important visual information is conveyed through alt text
13. ARIA Implementation Issues – 154 Violations
WCAG Reference: 4.1.2 Name, Role, Value – Level A
Common Problems
- Incorrect ARIA landmark usage
- Missing or wrong ARIA controls relationships
- Custom components without proper ARIA states
- Conflicting semantic markup and ARIA
- Improper live region implementation
βΌ
Essential Code Patterns
<!-- Correct ARIA landmark structure -->
<header role="banner">
<nav role="navigation" aria-label="Main navigation">
<ul>
<li><a href="#" aria-current="page">Home</a></li>
<li><a href="#">About</a></li>
</ul>
</nav>
</header>
<main role="main">
<section aria-labelledby="products-heading">
<h2 id="products-heading">Our Products</h2>
<!-- Expandable content with proper ARIA -->
<button aria-expanded="false"
aria-controls="product-details"
onclick="toggleDetails()">
Show Product Details
</button>
<div id="product-details" aria-hidden="true">
<p>Detailed product information...</p>
</div>
</section>
</main>
<!-- Live regions for dynamic content -->
<div id="status-polite" aria-live="polite" aria-atomic="true" class="sr-only"></div>
<div id="status-assertive" aria-live="assertive" aria-atomic="true" class="sr-only"></div>Testing ARIA
- Use screen readers (NVDA, JAWS, VoiceOver) to test ARIA announcements
- Browser DevTools accessibility tree to verify ARIA structure
- W3C Using ARIA Guide
- ARIA Authoring Practices Guide
π Interactive Demos: Part 2: ARIA Implementation – Live region and state management demos
Quick Test: Use screen reader β Navigate landmarks β Test dynamic content β Verify state changes are announced
14. Form Validation and Error Identification – 45 Violations
WCAG Reference: 3.3.1 Error Identification – Level A | 3.3.2 Labels or Instructions – Level A
Common Problems
- Form validation errors shown without proper identification
- Submit buttons with only icons and no text alternatives
- Toggle buttons missing state information (pressed/unpressed)
- Required fields not clearly marked
- Error messages not announced to screen readers
βΌ
Essential Code Patterns
<!-- Form with proper error handling -->
<form novalidate>
<label for="email">
Email Address
<span class="required" aria-label="required">*</span>
</label>
<input type="email"
id="email"
required
aria-describedby="email-error email-help"
aria-invalid="false">
<div id="email-help">We'll never share your email</div>
<div id="email-error" role="alert" aria-live="polite"></div>
<button type="submit" aria-describedby="submit-help">
<svg aria-hidden="true"><!-- submit icon --></svg>
Create Account
</button>
<div id="submit-help">By clicking, you agree to our terms</div>
</form>
<!-- JavaScript for error handling -->
<script>
function validateEmail(input) {
const errorDiv = document.getElementById('email-error');
if (!input.validity.valid) {
input.setAttribute('aria-invalid', 'true');
errorDiv.textContent = 'Please enter a valid email address';
} else {
input.setAttribute('aria-invalid', 'false');
errorDiv.textContent = '';
}
}
</script>π Interactive Demos: Part 2: Form Validation – Real-time validation demos
Quick Test: Submit form with errors β Check error messages are announced β Verify error association with fields
15. Page Language and Accessibility Name – 123 Violations
WCAG Reference: 3.1.1 Language of Page – Level A | 2.5.3 Label in Name – Level A
Common Problems
- Missing lang attribute on html element
- Accessible names that don’t match visible text
- Language changes not announced to screen readers
- Voice control users can’t activate elements by saying visible text
βΌ
Essential Code Patterns
<!-- Set page language -->
<html lang="en">
<!-- Language changes -->
<p>Welcome! <span lang="es">Β‘Bienvenidos!</span> <span lang="fr">Bienvenue!</span></p>
<!-- Accessible names that match visible text -->
<!-- BAD: Accessible name doesn't include visible text -->
<button aria-label="Submit form">Send Message</button>
<!-- GOOD: Accessible name starts with visible text -->
<button aria-label="Send Message - Submit contact form">Send Message</button>
<!-- Even better: Let visible text be the accessible name -->
<button>Send Message</button>π Interactive Demos: Part 3: Page Language – Multilingual examples
Quick Test: Check HTML lang attribute β Test voice control with button text β Verify language changes
Testing Checklist
Automated Testing
- Run axe-core in CI/CD pipeline
- Use WAVE browser extension
- Check color contrast with WebAIM tool
- Lighthouse Accessibility: Built into Chrome DevTools
Manual Testing
- Navigate entire site using only keyboard
- Test with screen reader (NVDA, JAWS, VoiceOver)
- Verify 400% zoom doesn’t break layout
- Check that all functionality works without color
- Validate HTML structure and semantics
- Keyboard Testing: Unplug your mouse and navigate with Tab, Arrow keys, Enter, Space
Code Review Points
- All images have appropriate alt text
- Forms have proper labels and validation
- Heading structure is logical (no skipped levels)
- Focus indicators are visible and have sufficient contrast
- Interactive elements are keyboard accessible
- Color is not the only way to convey information
Quick Reference Links
- WCAG 2.2 Guidelines: https://www.w3.org/TR/WCAG22/
- WCAG Quick Reference: https://www.w3.org/WAI/WCAG22/quickref/
- ARIA Authoring Practices: https://www.w3.org/WAI/ARIA/apg/
- WebAIM Resources: https://webaim.org/resources/
- MDN Accessibility: https://developer.mozilla.org/en-US/docs/Web/Accessibility
- A11y Project: https://www.a11yproject.com/
- Accessible Colors: https://accessible-colors.com/
- Axe DevTools: Browser extension for automated testing
