Claude Code Plugins

Community-maintained marketplace

Feedback

accessibility-implementation

@chriscarterux/chris-claude-stack
1
0

This skill should be used when implementing accessible interfaces and ensuring WCAG 2.1 compliance - covers ARIA labels, keyboard navigation, screen reader support, color contrast, focus management, and semantic HTML for inclusive design that works for all users.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name accessibility-implementation
description This skill should be used when implementing accessible interfaces and ensuring WCAG 2.1 compliance - covers ARIA labels, keyboard navigation, screen reader support, color contrast, focus management, and semantic HTML for inclusive design that works for all users.

Accessibility Implementation

Overview

Build interfaces that work for everyone, including users with disabilities. Meet WCAG 2.1 Level AA standards through systematic accessibility practices.

Core principle: Accessibility is not optional - it's a fundamental requirement for quality software.

When to Use

Use when:

  • Building new UI components
  • Required to meet WCAG compliance
  • Users report accessibility issues
  • Implementing forms, navigation, or interactive elements
  • Before launching to production
  • Working with accessibility-specialist agent

WCAG 2.1 Level AA Essentials

1. Perceivable

Color Contrast:

  • Normal text: 4.5:1 minimum
  • Large text (18pt+): 3:1 minimum
  • UI components: 3:1 minimum

Check contrast:

Tool: WebAIM Contrast Checker
https://webaim.org/resources/contrastchecker/

Don't rely on color alone:

❌ Red/green for error/success only
✅ Red + icon + text: "Error: Invalid email"

Alt text for images:

<img src="chart.png" alt="Revenue up 23% vs last month" />
// Not: alt="chart"
// Not: alt=""  (unless purely decorative)

2. Operable

Keyboard navigation:

  • All interactive elements focusable
  • Tab order makes sense
  • Enter/Space activate buttons
  • Escape closes modals
  • Arrow keys for menus/selects

Focus indicators:

button:focus-visible {
  outline: 2px solid #3B82F6;
  outline-offset: 2px;
}

/* Don't remove outlines! */
❌ *:focus {outline: none}

Skip links:

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

<main id="main-content">
  {/* Page content */}
</main>
.skip-link {
  position: absolute;
  top: -40px;
  left: 0;
  z-index: 100;
}

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

3. Understandable

Clear labels:

❌ <input placeholder="Enter text" />

✅ <label htmlFor="email">Email address</label>
   <input id="email" type="email" />

Error messages:

<input
  aria-invalid={hasError}
  aria-describedby={hasError ? "email-error" : undefined}
/>
{hasError && (
  <p id="email-error" role="alert">
    Please enter a valid email address
  </p>
)}

4. Robust

Semantic HTML:

✅ <button onClick={handleClick}>Click me</button>
❌ <div onClick={handleClick}>Click me</div>

✅ <nav><ul><li><a href="/about">About</a></li></ul></nav>
❌ <div><div><div onClick={navigate}>About</div></div></div>

ARIA Patterns

Buttons

<button
  type="button"
  aria-label="Close dialog"
  onClick={onClose}
>
  <X /> {/* Icon only */}
</button>

Links vs Buttons

Use <button> for actions (submit, open modal, toggle)
Use <a> for navigation (go to different page)
✅ <button onClick={openModal}>View Details</button>
❌ <a onClick={openModal}>View Details</a>

✅ <a href="/about">About Us</a>
❌ <button onClick={() => navigate('/about')}>About Us</button>

Form Controls

<label htmlFor="name">Full Name</label>
<input
  id="name"
  type="text"
  required
  aria-required="true"
  aria-describedby="name-help"
/>
<p id="name-help">Enter your first and last name</p>

Custom Components

// Custom checkbox
<div
  role="checkbox"
  aria-checked={checked}
  aria-label="Accept terms"
  tabIndex={0}
  onClick={toggle}
  onKeyDown={(e) => {
    if (e.key === ' ' || e.key === 'Enter') toggle()
  }}
>
  {checked ? <CheckIcon /> : <UncheckedIcon />}
</div>

Modals/Dialogs

<div
  role="dialog"
  aria-modal="true"
  aria-labelledby="dialog-title"
  aria-describedby="dialog-description"
>
  <h2 id="dialog-title">Confirm Delete</h2>
  <p id="dialog-description">
    This action cannot be undone.
  </p>
  <button onClick={onDelete}>Delete</button>
  <button onClick={onCancel}>Cancel</button>
</div>

Focus management:

useEffect(() => {
  if (isOpen) {
    // Focus first element
    const firstFocusable = dialogRef.current?.querySelector('button, [href], input')
    firstFocusable?.focus()

    // Trap focus inside dialog
    // Return focus on close
  }
}, [isOpen])

Keyboard Navigation

Standard Patterns

Element Keys Behavior
Button Enter, Space Activate
Link Enter Navigate
Checkbox Space Toggle
Radio Arrow keys Select option
Select Arrow keys, Enter Navigate, select
Tab Tab Next focusable
Tab Shift+Tab Previous focusable
Modal Escape Close
Menu Arrow keys, Escape Navigate, close

Implementation

function Button({onClick, children}: ButtonProps) {
  const handleKeyDown = (e: KeyboardEvent) => {
    if (e.key === 'Enter' || e.key === ' ') {
      e.preventDefault()
      onClick()
    }
  }

  return (
    <button
      onClick={onClick}
      onKeyDown={handleKeyDown}
      type="button"
    >
      {children}
    </button>
  )
}

Screen Reader Support

Announce Dynamic Content

// Live regions for updates
<div aria-live="polite" aria-atomic="true">
  {statusMessage}
</div>

// aria-live="polite": Announce when user is idle
// aria-live="assertive": Announce immediately (errors)
// aria-atomic="true": Read entire region, not just changes

Visually Hidden Text

// Text for screen readers only
<span className="sr-only">
  Loading...
</span>

<Spinner aria-hidden="true" />
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0,0,0,0);
  border: 0;
}

Loading States

<button disabled={isLoading} aria-busy={isLoading}>
  {isLoading ? (
    <>
      <Spinner aria-hidden="true" />
      <span className="sr-only">Loading...</span>
    </>
  ) : (
    'Submit'
  )}
</button>

Testing for Accessibility

Automated Testing

# Install axe
npm install --save-dev @axe-core/react

# Add to app (development only)
if (process.env.NODE_ENV !== 'production') {
  import('@axe-core/react').then(axe => {
    axe.default(React, ReactDOM, 1000)
  })
}

Manual Testing

Keyboard testing:

  1. Tab through entire page
  2. Activate all interactive elements with Enter/Space
  3. Escape closes modals
  4. Focus visible at all times
  5. Tab order logical

Screen reader testing:

  • Mac: VoiceOver (Cmd+F5)
  • Windows: NVDA (free)
  • Test critical flows (signup, checkout)

Lighthouse Audit

# Run Lighthouse in Chrome DevTools
# Accessibility score should be 90+

shadcn/ui Accessibility

Built-in accessibility:

  • All components keyboard navigable
  • ARIA attributes included
  • Focus management handled
  • Semantic HTML

Still required:

  • Meaningful labels
  • Error messages
  • Proper heading hierarchy
  • Sufficient color contrast

Example:

import {Button} from "@/components/ui/button"

// Already accessible:
// - Keyboard navigable
// - Focus styles
// - Proper semantics

// You add:
<Button aria-label="Delete item">
  <Trash2 />
</Button>

Common Mistakes

Mistake Impact Fix
Missing alt text Images invisible to screen readers Add descriptive alt text
Div buttons Not keyboard accessible Use <button> element
No focus indicators Can't see where you are Add :focus-visible styles
Color only for info Color blind users miss info Add text/icons too
Automatic media Unexpected sound/movement Require user interaction
Missing labels Forms unusable Label all inputs
Poor heading structure Can't navigate by headings Use h1-h6 properly

Quick Wins

Immediate improvements:

  1. Add alt text to all images
  2. Use semantic HTML (button, nav, header, main)
  3. Label all form inputs
  4. Ensure keyboard navigation works
  5. Add focus indicators
  6. Check color contrast
  7. Test with keyboard only

Expected: 90+ Lighthouse score in 1 day

Resources

  • WCAG 2.1: w3.org/WAI/WCAG21/quickref
  • ARIA patterns: w3.org/WAI/ARIA/apg
  • Contrast checker: webaim.org/resources/contrastchecker
  • axe DevTools: chrome extension

Accessibility isn't extra work - it's building products correctly. Start with semantic HTML, add ARIA when needed, test systematically.