MCPInstall

accessibility engineer

Implement accessibility (a11y) best practices to make applications usable by everyone. Use when building UIs, conducting accessibility audits, or ensuring WCAG compliance. Covers screen readers, keyboard navigation, ARIA attributes, and inclusive design patterns.

Installs
177
Last 24h
—
Trending rank
—
Security
Not audited

Install

Works with every agent the skills CLI supports.

npx skills add https://github.com/daffy0208/ai-dev-standards --skill accessibility-engineer
  1. 01

    Install

    Run the command in your project. The CLI asks which agents to install for.

  2. 02

    Describe the task

    Ask your agent for something this skill covers. It loads accessibility engineer automatically when relevant.

  3. 03

    Review the result

    The agent follows the SKILL.md steps, scripts and references bundled with the skill.

SKILL.md

The instructions your agent reads when the skill is triggered.

Accessibility Engineer

Build for everyone - accessibility is not optional.

Core Principle

Accessibility is a civil right, not a feature.

1 in 4 adults in the US has a disability. Accessible design benefits everyone:

  • Blind users (screen readers)
  • Low vision users (zoom, high contrast)
  • Deaf users (captions)
  • Motor disabilities (keyboard-only)
  • Cognitive disabilities (clear language)
  • Temporary disabilities (broken arm)
  • Situational limitations (bright sunlight, noisy environment)

WCAG Compliance Levels

Level A: Minimum (legal requirement) Level AA: Industry standard (aim for this) Level AAA: Gold standard (difficult to achieve for all content)

Target: WCAG 2.1 AA compliance


Pillar 1: Semantic HTML

Use the Right Elements

// ❌ Bad: Divs for everything (no semantic meaning)
<div onClick={handleClick}>Click me</div>
<div>Menu</div>

// ✅ Good: Semantic HTML
<button onClick={handleClick}>Click me</button>
<nav>Menu</nav>

Document Structure

// ✅ Proper heading hierarchy
<h1>Page Title</h1>
  <h2>Section 1</h2>
    <h3>Subsection 1.1</h3>
  <h2>Section 2</h2>

// ❌ Bad: Skipping levels
<h1>Page Title</h1>
  <h4>Section 1</h4> // Skipped h2, h3

Landmarks

<header>
  <nav aria-label="Main navigation">
    {/* Navigation links */}
  </nav>
</header>

<main>
  <article>
    {/* Main content */}
  </article>

  <aside>
    {/* Sidebar */}
  </aside>
</main>

<footer>
  {/* Footer content */}
</footer>

Pillar 2: Keyboard Navigation

All Interactive Elements Must Be Keyboard Accessible

// ✅ Button is keyboard accessible by default
<button onClick={handleClick}>Click me</button>

// ❌ Div requires extra work
<div onClick={handleClick}>Click me</div> // Can't tab to it!

// ✅ If you must use div, add keyboard support
<div
  role="button"
  tabIndex={0}
  onClick={handleClick}
  onKeyDown={(e) => {
    if (e.key === 'Enter' || e.key === ' ') {
      handleClick()
    }
  }}
>
  Click me
</div>

Tab Order

// ✅ Natural tab order (follows DOM order)
<input />
<button>Submit</button>
<a href="/help">Help</a>

// ❌ Don't use tabIndex > 0 (breaks natural order)
<button tabIndex={5}>Button</button> // Anti-pattern!

// ✅ tabIndex=-1 to remove from tab order
<div tabIndex={-1}>Not keyboard focusable</div>

Focus Management

// Modal: Trap focus inside
function Modal({ isOpen, onClose, children }) {
  const modalRef = useRef()

  useEffect(() => {
    if (!isOpen) return

    // Focus first focusable element
    const firstFocusable = modalRef.current.querySelector('button, input, a')
    firstFocusable?.focus()

    // Trap focus
    function handleTab(e) {
      if (e.key !== 'Tab') return

      const focusableElements = modalRef.current.querySelectorAll(
        'button, input, a, [tabindex]:not([tabindex="-1"])'
      )

      const first = focusableElements[0]
      const last = focusableElements[focusableElements.length - 1]

      if (e.shiftKey) {
        if (document.activeElement === first) {
          last.focus()
          e.preventDefault()
        }
      } else {
        if (document.activeElement === last) {
          first.focus()
          e.preventDefault()
        }
      }
    }

    document.addEventListener('keydown', handleTab)
    return () => document.removeEventListener('keydown', handleTab)
  }, [isOpen])

  return isOpen ? (
    <div role="dialog" aria-modal="true" ref={modalRef}>
      {children}
      <button onClick={onClose}>Close</button>
    </div>
  ) : null
}

Skip Links

// Allow keyboard users to skip navigation
<a href="#main-content" className="skip-link">
  Skip to main content
</a>

<nav>{/* Navigation */}</nav>

<main id="main-content">
  {/* Main content */}
</main>

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

.skip-link:focus {
  top: 0;
}

Pillar 3: ARIA Attributes

Only Use ARIA When Semantic HTML Isn't Enough

// ✅ Semantic HTML (no ARIA needed)
<button>Click me</button>

// ❌ Unnecessary ARIA
<button role="button" aria-label="Click me">Click me</button>

// ✅ ARIA needed (custom widget)
<div role="tab" aria-selected={isActive} aria-controls="panel-1">
  Tab 1
</div>

Common ARIA Attributes

aria-label - Provides accessible name:

<button aria-label="Close dialog">
  <XIcon /> {/* Visual only */}
</button>

<input type="search" aria-label="Search products" />

aria-labelledby - References another element:

<h2 id="dialog-title">Delete Account</h2>
<div role="dialog" aria-labelledby="dialog-title">
  {/* Dialog content */}
</div>

aria-describedby - Additional description:

<input
  type="password"
  aria-describedby="password-requirements"
/>
<div id="password-requirements">
  Must be at least 8 characters
</div>

aria-live - Announce dynamic content:

// Polite: Wait for user to finish
<div aria-live="polite">
  {itemsAddedToCart} items added to cart
</div>

// Assertive: Interrupt immediately (use sparingly)
<div aria-live="assertive" role="alert">
  Error: Payment failed
</div>

aria-expanded - Collapsible content:

<button
  aria-expanded={isOpen}
  aria-controls="dropdown-menu"
  onClick={() => setIsOpen(!isOpen)}
>
  Menu
</button>

<div id="dropdown-menu" hidden={!isOpen}>
  {/* Menu items */}
</div>

aria-hidden - Hide from screen readers:

// Decorative icons
<span aria-hidden="true">★</span>

// Don't hide interactive elements!
// ❌ Bad
<button aria-hidden="true">Click me</button>

Pillar 4: Forms & Inputs

Labels

// ✅ Good: Explicit label
<label htmlFor="email">Email</label>
<input id="email" type="email" />

// ✅ Good: Implicit label
<label>
  Email
  <input type="email" />
</label>

// ❌ Bad: No label (placeholder is not a label!)
<input type="email" placeholder="Email" />

Error Messages

function EmailInput({ error }) {
  const errorId = 'email-error'

  return (
    <>
      <label htmlFor="email">Email</label>
      <input
        id="email"
        type="email"
        aria-invalid={!!error}
        aria-describedby={error ? errorId : undefined}
      />
      {error && (
        <div id={errorId} role="alert">
          {error}
        </div>
      )}
    </>
  )
}

Required Fields

<label htmlFor="name">
  Name <span aria-label="required">*</span>
</label>
<input id="name" type="text" required aria-required="true" />

Pillar 5: Color & Contrast

Minimum Contrast Ratios (WCAG AA)

  • Normal text (< 18pt): 4.5:1
  • Large text (≥ 18pt or 14pt bold): 3:1
  • UI components: 3:1
// ❌ Bad: Insufficient contrast
<button style={{ background: '#ddd', color: '#aaa' }}>
  Submit // 1.5:1 contrast - fails!
</button>

// ✅ Good: Sufficient contrast
<button style={{ background: '#0066cc', color: '#ffffff' }}>
  Submit // 8:1 contrast - passes!
</button>

Don't Use Color Alone

// ❌ Bad: Color only
<span style={{ color: 'red' }}>Error</span>
<span style={{ color: 'green' }}>Success</span>

// ✅ Good: Color + icon/text
<span style={{ color: 'red' }}>
  <ErrorIcon aria-hidden="true" />
  Error
</span>

Pillar 6: Images & Media

Alt Text

// ✅ Informative images
<img src="chart.png" alt="Sales increased 50% in Q4" />

// ✅ Decorative images
<img src="decorative-border.png" alt="" /> // Empty alt

// ❌ Bad: No alt or redundant alt
<img src="photo.jpg" /> // Missing alt
<img src="photo.jpg" alt="Photo" /> // Useless

Complex Images

<figure>
  <img src="complex-chart.png" alt="Sales data for 2024" />
  <figcaption>
    <details>
      <summary>Detailed description</summary>
      <p>Q1: $100k, Q2: $150k, Q3: $180k, Q4: $220k. Shows 50% growth year-over-year.</p>
    </details>
  </figcaption>
</figure>

Video Captions

<video controls>
  <source src="video.mp4" type="video/mp4" />
  <track kind="captions" src="captions.vtt" srclang="en" label="English" default />
</video>

Pillar 7: Testing

Automated Testing

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

# axe-core (Jest)
npm install --save-dev @axe-core/react jest-axe
// Test with jest-axe
import { axe, toHaveNoViolations } from 'jest-axe'

expect.extend(toHaveNoViolations)

it('has no accessibility violations', async () => {
  const { container } = render(<Button>Click me</Button>)
  const results = await axe(container)

  expect(results).toHaveNoViolations()
})

Manual Testing

Keyboard Navigation:

  • Tab through entire page
  • Enter/Space to activate buttons
  • Arrow keys for radio groups
  • Esc to close modals

Screen Reader Testing:

  • NVDA (Windows, free)
  • JAWS (Windows, paid)
  • VoiceOver (Mac, built-in)

Screen Reader Shortcuts:

  • Navigate by headings: H (next), Shift+H (previous)
  • Navigate by landmarks: D (next), Shift+D (previous)
  • List all links: Insert+F7 (NVDA)

Common Patterns

Accessible Button

<button
  type="button"
  onClick={handleClick}
  disabled={isDisabled}
  aria-busy={isLoading}
  aria-label={ariaLabel}
>
  {children}
</button>

Accessible Modal

<div
  role="dialog"
  aria-modal="true"
  aria-labelledby="dialog-title"
  aria-describedby="dialog-description"
>
  <h2 id="dialog-title">Dialog Title</h2>
  <p id="dialog-description">Dialog description</p>

  <button onClick={onClose}>Close</button>
</div>

Accessible Tabs

<div>
  <div role="tablist">
    <button
      role="tab"
      aria-selected={activeTab === 'tab1'}
      aria-controls="panel1"
      onClick={() => setActiveTab('tab1')}
    >
      Tab 1
    </button>
    <button
      role="tab"
      aria-selected={activeTab === 'tab2'}
      aria-controls="panel2"
      onClick={() => setActiveTab('tab2')}
    >
      Tab 2
    </button>
  </div>

  <div id="panel1" role="tabpanel" hidden={activeTab !== 'tab1'}>
    Panel 1 content
  </div>

  <div id="panel2" role="tabpanel" hidden={activeTab !== 'tab2'}>
    Panel 2 content
  </div>
</div>

Accessibility Checklist

Semantic HTML

  • Proper heading hierarchy (h1 → h2 → h3)
  • Semantic landmarks (header, nav, main, footer)
  • Lists use ul/ol/li
  • Buttons for actions, links for navigation

Keyboard

  • All interactive elements keyboard accessible
  • Visible focus indicators
  • Logical tab order
  • Skip links provided
  • No keyboard traps

ARIA

  • Semantic HTML used first (ARIA only when needed)
  • All interactive widgets have roles
  • Dynamic content has aria-live
  • Forms have proper labels and descriptions

Color & Contrast

  • Text contrast ≥ 4.5:1 (normal), ≥ 3:1 (large)
  • Don't use color alone to convey info
  • Focus indicators visible

Images & Media

  • All images have alt text
  • Decorative images have empty alt
  • Videos have captions
  • Audio has transcripts

Forms

  • All inputs have labels
  • Error messages associated with inputs
  • Required fields indicated

Testing

  • Keyboard navigation tested
  • Screen reader tested
  • Automated tools run (axe, Lighthouse)
  • Color blindness simulation tested

Tools

  • axe DevTools - Browser extension
  • Lighthouse - Built into Chrome DevTools
  • WAVE - Web accessibility evaluation tool
  • Color Contrast Analyzer - Desktop app
  • NVDA - Free screen reader (Windows)
  • VoiceOver - Built-in screen reader (Mac)

Related Resources

Skills:

  • ux-designer - Accessible design patterns
  • frontend-builder - Accessible React components
  • testing-strategist - Accessibility testing

External:


Build for everyone. ♿

FAQ

What does the accessibility engineer skill do?

Implement accessibility (a11y) best practices to make applications usable by everyone. Use when building UIs, conducting accessibility audits, or ensuring WCAG compliance. Covers screen readers, keyboard navigation, ARIA attributes, and inclusive design patterns.

How do I install accessibility engineer?

Run npx skills add https://github.com/daffy0208/ai-dev-standards --skill accessibility-engineer in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/accessibility-engineer/ (personal) or .claude/skills/accessibility-engineer/ (project).

Which AI agents can use accessibility engineer?

Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.

Is accessibility engineer safe to install?

No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.

Who maintains accessibility engineer?

It is published by daffy0208 in daffy0208/ai-dev-standards. It has 177 recorded installs.

More from daffy0208/ai-dev-standards

View all →

animation-designer

daffy0208/ai-dev-standards

Expert in web animations, transitions, and motion design using Framer Motion and CSS

Frontend & Design1.9K installs

brand-designer

daffy0208/ai-dev-standards

Expert in brand identity, logo design, and visual brand systems

Marketing & SEO1.3K installs

3d-visualizer

daffy0208/ai-dev-standards

Expert in Three.js, 3D graphics, and interactive 3D visualizations

Media & Creative665 installs

data-visualizer

daffy0208/ai-dev-standards

Expert in creating charts, dashboards, and data visualizations using modern libraries

572 installs

video-producer

daffy0208/ai-dev-standards

Expert in video playback, streaming, and video player customization

Media & Creative449 installs

knowledge base manager

daffy0208/ai-dev-standards

Open the skill to read its SKILL.md instructions.

438 installs

Popular frontend & design skills

View category →

setup-matt-pocock-skills

mattpocock/skills

Configure this repo for the engineering skills: set up its issue tracker, triage label vocabulary, and domain doc layout. Run once before first use of the other engineering skills.

Frontend & Design1.1M installs

frontend-design

anthropics/skills

Guidance for distinctive, intentional visual design when building new UI or reshaping an existing one. Helps with aesthetic direction, typography, and making choices that don't read as templated defaults.

OfficialFrontend & Design1M installs

hyperframes-animation

heygen-com/hyperframes

All animation knowledge for HyperFrames — atomic motion rules, multi-phase scene blueprints, scene transitions, broader motion-design techniques, AND the seven runtime adapters (GSAP default, plus Lottie, Three.js, Anime.js, CSS keyframes, Web Animations API, TypeGPU). Use for any motion or animation task: pick 2-4 rules and compose, or load a blueprint, or look up runtime-specific API (e.g. GSAP eases / Lottie player / Three.js mixer). Also covers auditing an existing composition's choreography (animation map) and 24 named text-animation effects. HyperFrames-native: single paused timeline, seek-safe, deterministic.

prototype

mattpocock/skills

Build a throwaway prototype to answer a design question. Use when the user wants to sanity-check whether a state model or logic feels right, or explore what a UI should look like.

Frontend & Design999.2K installs

hyperframes-core

heygen-com/hyperframes

The HyperFrames composition contract — build one renderable project. Use for composition structure, the data- timing attributes, class="clip", tracks, sub-compositions, variables, framework-owned media playback, deterministic-render rules, and validation. Read before writing composition HTML.

Frontend & Design930.5K installs

vercel-react-best-practices

vercel-labs/agent-skills

React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.

OfficialFrontend & Design843.1K installs