accessibility-wcag
Accessibility & WCAG Compliance
Build inclusive, accessible interfaces that work for all users.
Instructions
- Use semantic HTML first - ARIA is a last resort, not a first choice
- Ensure keyboard navigation - All interactive elements must be keyboard accessible
- Provide text alternatives - Images, icons, and media need accessible descriptions
- Maintain focus visibility - Never remove focus outlines without replacement
- Test with assistive technologies - Use screen readers and keyboard-only navigation
WCAG 2.1 AA Requirements
Color Contrast Ratios
- Normal text: 4.5:1 minimum
- Large text (18pt+ or 14pt bold): 3:1 minimum
- UI components: 3:1 minimum
- Focus indicators: 3:1 minimum
Focus Management
// Visible focus styles
<button className="
focus:outline-none
focus-visible:ring-2
focus-visible:ring-blue-500
focus-visible:ring-offset-2
">
Click me
</button>
// Focus trap for modals
import { FocusTrap } from '@headlessui/react';
function Modal({ isOpen, children }) {
return isOpen ? (
<FocusTrap>
<div role="dialog" aria-modal="true">
{children}
</div>
</FocusTrap>
) : null;
}
Semantic HTML
Use Correct Elements
// Good - semantic
<nav aria-label="Main navigation">
<ul>
<li><a href="/home">Home</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
<main>
<article>
<header>
<h1>Article Title</h1>
<time dateTime="2024-01-15">January 15, 2024</time>
</header>
<section aria-labelledby="intro">
<h2 id="intro">Introduction</h2>
<p>Content...</p>
</section>
</article>
</main>
// Bad - div soup
<div class="nav">
<div class="nav-item">Home</div>
</div>
Heading Hierarchy
// Correct heading order
<h1>Page Title</h1> // Only one per page
<h2>Section</h2>
<h3>Subsection</h3>
<h3>Subsection</h3>
<h2>Section</h2>
<h3>Subsection</h3>
ARIA Patterns
Live Regions
// Announce dynamic changes
<div
role="status"
aria-live="polite"
aria-atomic="true"
>
{statusMessage}
</div>
// For urgent alerts
<div
role="alert"
aria-live="assertive"
>
{errorMessage}
</div>
Accessible Forms
function AccessibleForm() {
const [errors, setErrors] = useState<Record<string, string>>({});
return (
<form aria-describedby="form-instructions">
<p id="form-instructions" className="sr-only">
Required fields are marked with an asterisk
</p>
<div>
<label htmlFor="email">
Email <span aria-hidden="true">*</span>
<span className="sr-only">(required)</span>
</label>
<input
id="email"
type="email"
required
aria-required="true"
aria-invalid={!!errors.email}
aria-describedby={errors.email ? "email-error" : undefined}
/>
{errors.email && (
<p id="email-error" role="alert" className="text-red-600">
{errors.email}
</p>
)}
</div>
<button type="submit">Submit</button>
</form>
);
}
Accessible Buttons
// Icon-only button
<button
type="button"
aria-label="Close dialog"
onClick={onClose}
>
<XIcon aria-hidden="true" />
</button>
// Toggle button
<button
type="button"
aria-pressed={isActive}
onClick={() => setIsActive(!isActive)}
>
{isActive ? 'Active' : 'Inactive'}
</button>
// Loading button
<button
type="submit"
disabled={isLoading}
aria-busy={isLoading}
aria-disabled={isLoading}
>
{isLoading ? (
<>
<Spinner aria-hidden="true" />
<span className="sr-only">Loading...</span>
</>
) : (
'Submit'
)}
</button>
Accessible Modal
function AccessibleModal({ isOpen, onClose, title, children }) {
const modalRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (isOpen) {
// Store current focus
const previousFocus = document.activeElement;
// Focus modal
modalRef.current?.focus();
// Handle escape key
const handleEscape = (e: KeyboardEvent) => {
if (e.key === 'Escape') onClose();
};
document.addEventListener('keydown', handleEscape);
// Trap focus and restore on close
return () => {
document.removeEventListener('keydown', handleEscape);
(previousFocus as HTMLElement)?.focus();
};
}
}, [isOpen, onClose]);
if (!isOpen) return null;
return (
<div
role="dialog"
aria-modal="true"
aria-labelledby="modal-title"
ref={modalRef}
tabIndex={-1}
>
<h2 id="modal-title">{title}</h2>
{children}
<button onClick={onClose}>Close</button>
</div>
);
}
Keyboard Navigation
Required Keyboard Support
| Element | Keys |
|---|---|
| Buttons | Enter, Space |
| Links | Enter |
| Checkboxes | Space |
| Radio buttons | Arrow keys |
| Tabs | Arrow keys, Home, End |
| Menus | Arrow keys, Enter, Escape |
| Modals | Tab (trapped), Escape |
Skip Link
// First element in body
<a
href="#main-content"
className="
sr-only focus:not-sr-only
focus:absolute focus:top-4 focus:left-4
focus:z-50 focus:bg-white focus:px-4 focus:py-2
"
>
Skip to main content
</a>
<main id="main-content" tabIndex={-1}>
{/* Page content */}
</main>
Screen Reader Utilities
/* Visually hidden but screen reader accessible */
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
/* Show on focus (for skip links) */
.sr-only-focusable:focus {
position: static;
width: auto;
height: auto;
margin: 0;
overflow: visible;
clip: auto;
white-space: normal;
}
Testing Checklist
Automated Testing
- Run axe-core or similar automated a11y scanner
- Check color contrast with browser devtools
- Validate HTML for semantic correctness
Manual Testing
- Navigate entire page with keyboard only (Tab, Enter, Space, Arrow keys)
- Test with screen reader (NVDA, VoiceOver, JAWS)
- Verify focus is visible and logical order
- Check all images have alt text
- Verify form labels are associated
- Test at 200% zoom
Screen Reader Testing Commands
VoiceOver (Mac)
- Cmd + F5: Toggle VoiceOver
- Ctrl + Option + arrows: Navigate
- Ctrl + Option + Space: Activate
NVDA (Windows)
- Insert + Space: Toggle browse mode
- H: Next heading
- Tab: Next focusable element
Common Issues to Avoid
- Missing alt text - Every
<img>needs alt (empty for decorative) - Missing form labels - Every input needs associated label
- Low contrast - Check all text meets 4.5:1 ratio
- Keyboard traps - Users must be able to navigate away
- Missing focus styles - Never
outline: nonewithout replacement - Auto-playing media - Provide pause controls
- Timing issues - Avoid time limits or provide extensions
When to Use
- Building any web application
- Conducting accessibility audits
- Fixing a11y issues
- Creating component libraries
- Meeting legal compliance requirements
Notes
- WCAG 2.1 AA is the standard requirement for most organizations
- Some industries require AAA compliance
- Test with real users with disabilities when possible
- Accessibility benefits all users (SEO, mobile, etc.)
More from housegarofalo/claude-code-base
power-automate
Expert guidance for Power Automate development including cloud flows, desktop flows, Dataverse connector, expression functions, custom connectors, error handling, and child flow patterns. Use when building automated workflows, writing flow expressions, creating custom connectors from OpenAPI, or implementing error handling patterns.
5mobile-pwa
Build Progressive Web Apps with offline support, push notifications, and native-like experiences. Covers service workers, Web App Manifest, caching strategies, IndexedDB, background sync, and installability. Use for mobile-first web apps, offline-capable applications, and app-like experiences.
5cloudflare
Cloudflare services management including DNS, Tunnels (Argo), Zero Trust, WAF, CDN, Workers, and Pages. Configure domains, create tunnels for exposing local services, manage firewall rules, and optimize web performance. Use when working with Cloudflare, DNS management, reverse proxies, DDoS protection, or secure remote access.
4security-auditor-agent
Comprehensive security audit agent that performs systematic vulnerability assessment, threat modeling, and security compliance checks. Covers OWASP Top 10, dependency scanning, secret detection, infrastructure security, and compliance frameworks. Use for security audits, penetration test preparation, compliance assessments, or security hardening initiatives.
4dashboard-design
Design effective dashboards with clear layouts, KPI displays, data grids, and real-time updates. Covers dashboard patterns, information hierarchy, responsive grids, widget design, and admin panel layouts. Use for building analytics dashboards, admin interfaces, and monitoring displays.
4markitdown
Expert guidance for converting files to Markdown using Microsoft's MarkItDown utility. Convert PDF, Word, PowerPoint, Excel, images, audio, HTML, CSV, JSON, XML, ZIP, and EPub files to LLM-friendly Markdown format. Use when processing documents for AI analysis, extracting content from files, or preparing data for language models. Triggers on markitdown, document conversion, pdf to markdown, docx to markdown, file extraction, document processing.
4