accessibility

Implement web accessibility (a11y) best practices following WCAG guidelines. Ensure inclusive design for users with disabilities.

SKILL.md

GitHub

Web Accessibility (a11y)

This skill guides you through implementing web accessibility best practices following WCAG guidelines to create inclusive experiences for users with disabilities.

When to use this skill

Use this skill when you need to:

  • Audit and fix accessibility issues
  • Design accessible user interfaces
  • Implement keyboard navigation
  • Create screen reader compatible content
  • Meet WCAG compliance requirements

Prerequisites

  • Understanding of WCAG 2.1 guidelines
  • Accessibility testing tools (axe, Lighthouse, WAVE)
  • Screen reader (NVDA, JAWS, VoiceOver)
  • Keyboard-only navigation testing

Guidelines

WCAG Principles (POUR)

Perceivable

  • Text alternatives for images
  • Captions/transcripts for media
  • Color not sole means of conveying info
  • Resizable text up to 200%

Operable

  • All functionality available via keyboard
  • No time limits or adjustable
  • No seizure-inducing content
  • Clear navigation

Understandable

  • Readable text (simple language)
  • Predictable behavior
  • Input error prevention
  • Helpful error messages

Robust

  • Compatible with assistive technologies
  • Valid HTML
  • Consistent implementation

Semantic HTML

Structure

<!-- ✅ Good: Semantic structure -->
<header>
  <nav aria-label="Main">
    <ul>
      <li><a href="/" aria-current="page">Home</a></li>
      <li><a href="/about">About</a></li>
    </ul>
  </nav>
</header>

<main>
  <h1>Page Title</h1>
  <section aria-labelledby="products-heading">
    <h2 id="products-heading">Products</h2>
    <!-- content -->
  </section>
</main>

<footer>
  <p>&copy; 2024 Company</p>
</footer>

<!-- ❌ Bad: Div soup -->
<div class="header">
  <div class="nav">
    <div class="nav-item">Home</div>
  </div>
</div>

Form Labels

<!-- ✅ Good: Associated labels -->
<label for="email">Email Address</label>
<input type="email" id="email" name="email" required>

<!-- Or using aria-label -->
<input type="search" aria-label="Search products" placeholder="Search...">

<!-- Or using aria-labelledby -->
<span id="username-label">Username</span>
<input type="text" aria-labelledby="username-label">

<!-- ❌ Bad: No label association -->
<input type="email" placeholder="Enter email">

Keyboard Navigation

Focus Management

/* Visible focus indicators */
:focus {
  outline: 2px solid #005fcc;
  outline-offset: 2px;
}

/* Skip links */
.skip-link {
  position: absolute;
  top: -40px;
  left: 0;
  background: #000;
  color: #fff;
  padding: 8px;
}

.skip-link:focus {
  top: 0;
}
<!-- Skip navigation link -->
<a href="#main-content" class="skip-link">Skip to main content</a>

<main id="main-content">
  <!-- Page content -->
</main>

Focus Trap in Modals

// Manage focus within modal
function openModal() {
  modal.show();
  firstFocusableElement.focus();
  document.addEventListener('keydown', trapFocus);
}

function trapFocus(e) {
  if (e.key === 'Tab') {
    if (e.shiftKey && document.activeElement === firstFocusableElement) {
      e.preventDefault();
      lastFocusableElement.focus();
    } else if (!e.shiftKey && document.activeElement === lastFocusableElement) {
      e.preventDefault();
      firstFocusableElement.focus();
    }
  }
  if (e.key === 'Escape') {
    closeModal();
  }
}

ARIA Attributes

Landmarks

<header role="banner">...</header>
<nav role="navigation">...</nav>
<main role="main">...</main>
<aside role="complementary">...</aside>
<footer role="contentinfo">...</footer>

Dynamic Content

<!-- Live regions for announcements -->
<div aria-live="polite" aria-atomic="true" id="status-region">
  <!-- Status messages inserted here -->
</div>

<!-- Progress indication -->
<div role="progressbar" aria-valuenow="50" aria-valuemin="0" 
     aria-valuemax="100" aria-label="Upload progress">
  50%
</div>

Accessible Components

<!-- Button vs Link -->
<button type="button" onclick="submitForm()">Submit</button>
<a href="/page">Navigate to Page</a>

<!-- Tabs -->
<div role="tablist">
  <button role="tab" aria-selected="true" id="tab-1" 
          aria-controls="panel-1">Tab 1</button>
  <button role="tab" aria-selected="false" id="tab-2"
          aria-controls="panel-2">Tab 2</button>
</div>
<div role="tabpanel" id="panel-1" aria-labelledby="tab-1">...</div>

Images and Media

Alt Text Guidelines

<!-- Decorative image: empty alt -->
<img src="decorative-border.png" alt="">

<!-- Informative image: descriptive alt -->
<img src="chart.png" alt="Sales increased 50% from January to June">

<!-- Complex image: long description -->
<img src="complex-diagram.png" alt="Workflow diagram" 
     aria-describedby="diagram-desc">
<div id="diagram-desc" class="sr-only">
  Detailed description of the workflow...
</div>

<!-- SVG icons -->
<svg role="img" aria-label="Close">
  <use href="#icon-close">
</svg>

Media

<!-- Video with captions -->
<video controls>
  <source src="video.mp4" type="video/mp4">
  <track kind="captions" src="captions.vtt" srclang="en" label="English">
  <track kind="descriptions" src="descriptions.vtt" srclang="en">
</video>

<!-- Audio with transcript -->
<audio controls>
  <source src="podcast.mp3" type="audio/mpeg">
</audio>
<a href="transcript.html">Read transcript</a>

Color and Contrast

Contrast Requirements

  • Normal text: 4.5:1 ratio
  • Large text (18pt+): 3:1 ratio
  • UI components: 3:1 ratio
/* ✅ Good: Sufficient contrast */
.text {
  color: #333; /* Dark gray on white: 12.6:1 */
}

.button {
  background: #0066cc;
  color: #ffffff; /* 4.6:1 */
}

/* Don't rely on color alone */
.error {
  color: #d32f2f;
}
.error::before {
  content: "✕ "; /* Visual indicator */
}

Testing

Automated Testing

# axe-core CLI
axe https://example.com

# Lighthouse CI
lighthouse https://example.com --only-categories=accessibility

# Pa11y
pa11y https://example.com

Manual Testing

  • Keyboard-only navigation (Tab, Enter, Space, Arrow keys)
  • Screen reader testing (NVDA, VoiceOver, JAWS)
  • Zoom to 200% and 400%
  • Color contrast analyzer

Examples

See the examples/ directory for:

  • accessible-components/ - ARIA-compliant components
  • form-patterns/ - Accessible form implementations
  • focus-management/ - Focus handling utilities
  • testing-checklist.md - Accessibility testing checklist

References