
Accessibility Compliance
- 434 installs
- 305 repo stars
- Updated March 4, 2026
- aj-geddes/useful-ai-prompts
accessibility-compliance is an aj-geddes/useful-ai-prompts agent skill that audits and implements WCAG 2.1/2.2 accessibility patterns for developers shipping inclusive web UIs.
About
accessibility-compliance is an aj-geddes/useful-ai-prompts Claude Code skill from a library of 260+ skills and 488+ validated prompts. It implements WCAG 2.1/2.2 AA and AAA patterns including semantic HTML, ARIA usage, keyboard navigation, focus management, screen reader announcements, and color contrast validation at a 4.5:1 minimum for normal text. Six reference guides cover semantic HTML with ARIA, React accessible components, keyboard handlers, contrast validators, screen reader live regions, and focus trapping. Quick-start examples contrast non-semantic div buttons with proper button elements, tabindex handling, and labeled form fields. The skill supports audits for NVDA, JAWS, and VoiceOver compatibility and ADA or Section 508 alignment. Developers reach for accessibility-compliance before release or during pre-ship design review when components need measurable a11y remediation rather than ad-hoc fixes.
- WCAG-oriented audit prompt patterns
- Keyboard and focus-order checks
- Color contrast and readable text rules
- ARIA labels and semantic HTML review
- Remediation suggestions for common violations
Accessibility Compliance by the numbers
- 434 all-time installs (skills.sh)
- Ranked #657 of 1,880 Design & UI/UX skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/aj-geddes/useful-ai-prompts --skill accessibility-complianceAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 434 |
|---|---|
| repo stars | ★ 305 |
| Last updated | March 4, 2026 |
| Repository | aj-geddes/useful-ai-prompts ↗ |
How do you audit web components for WCAG compliance?
Audit pages and components for WCAG-oriented accessibility issues—contrast, keyboard paths, labels, focus order—before release or during pre-ship design review.
Who is it for?
Frontend developers preparing public-facing React or HTML apps for WCAG 2.1/2.2 AA audits and screen reader compatibility.
Skip if: Native mobile-only apps without web markup or teams that only need automated Lighthouse runs without component-level remediation patterns.
When should I use this skill?
Pages or components need pre-ship accessibility review for contrast, keyboard navigation, labels, or focus management.
What you get
Remediation checklists, accessible component code snippets, contrast fixes, and keyboard navigation handlers
- Accessible component snippets
- Contrast remediation guidance
- Keyboard navigation handlers
By the numbers
- Includes 6 reference guides in the references/ directory
- Targets WCAG 2.1/2.2 with 4.5:1 minimum color contrast for normal text
- From useful-ai-prompts library with 260+ Claude Code skills
Files
Accessibility Compliance
Table of Contents
Overview
Implement comprehensive accessibility features following WCAG guidelines to ensure your application is usable by everyone, including people with disabilities.
When to Use
- Building public-facing web applications
- Ensuring WCAG 2.1/2.2 AA or AAA compliance
- Supporting screen readers (NVDA, JAWS, VoiceOver)
- Implementing keyboard-only navigation
- Meeting ADA, Section 508, or similar regulations
- Improving SEO and overall user experience
- Conducting accessibility audits
Quick Start
Minimal working example:
<!-- Bad: Non-semantic markup -->
<div class="button" onclick="submit()">Submit</div>
<!-- Good: Semantic HTML -->
<button type="submit" aria-label="Submit form">Submit</button>
<!-- Custom components with proper ARIA -->
<div
role="button"
tabindex="0"
aria-pressed="false"
onclick="toggle()"
onkeydown="handleKeyPress(event)"
>
Toggle Feature
</div>
<!-- Form with proper labels and error handling -->
<form>
<label for="email">Email Address</label>
<input
id="email"
type="email"
name="email"
aria-required="true"
// ... (see reference guides for full implementation)Reference Guides
Detailed implementations in the references/ directory:
| Guide | Contents |
|---|---|
| Semantic HTML with ARIA | Semantic HTML with ARIA |
| React Component with Accessibility | React Component with Accessibility |
| Keyboard Navigation Handler | Keyboard Navigation Handler |
| Color Contrast Validator | Color Contrast Validator |
| Screen Reader Announcements | Screen Reader Announcements |
| Focus Management | Focus Management |
Best Practices
✅ DO
- Use semantic HTML elements
- Provide text alternatives for images
- Ensure sufficient color contrast (4.5:1 minimum)
- Support keyboard navigation
- Implement focus management
- Test with screen readers
- Use ARIA attributes correctly
- Provide skip links
- Make forms accessible with labels
- Support text resizing up to 200%
❌ DON'T
- Rely solely on color to convey information
- Remove focus indicators
- Use only mouse/touch interactions
- Auto-play media without controls
- Create keyboard traps
- Use positive tabindex values
- Override user preferences
- Hide content only visually that should be hidden from screen readers
Color Contrast Validator
Color Contrast Validator
from typing import Tuple
import math
def hex_to_rgb(hex_color: str) -> Tuple[int, int, int]:
"""Convert hex color to RGB."""
hex_color = hex_color.lstrip('#')
return tuple(int(hex_color[i:i+2], 16) for i in (0, 2, 4))
def calculate_luminance(rgb: Tuple[int, int, int]) -> float:
"""Calculate relative luminance."""
def adjust(color: int) -> float:
c = color / 255.0
if c <= 0.03928:
return c / 12.92
return math.pow((c + 0.055) / 1.055, 2.4)
r, g, b = rgb
return 0.2126 * adjust(r) + 0.7152 * adjust(g) + 0.0722 * adjust(b)
def calculate_contrast_ratio(color1: str, color2: str) -> float:
"""Calculate WCAG contrast ratio between two colors."""
lum1 = calculate_luminance(hex_to_rgb(color1))
lum2 = calculate_luminance(hex_to_rgb(color2))
lighter = max(lum1, lum2)
darker = min(lum1, lum2)
return (lighter + 0.05) / (darker + 0.05)
def check_wcag_compliance(
foreground: str,
background: str,
level: str = 'AA',
large_text: bool = False
) -> dict:
"""Check if color combination meets WCAG standards."""
ratio = calculate_contrast_ratio(foreground, background)
# WCAG 2.1 requirements
requirements = {
'AA': {'normal': 4.5, 'large': 3.0},
'AAA': {'normal': 7.0, 'large': 4.5}
}
required_ratio = requirements[level]['large' if large_text else 'normal']
passes = ratio >= required_ratio
return {
'ratio': round(ratio, 2),
'required': required_ratio,
'passes': passes,
'level': level,
'grade': 'Pass' if passes else 'Fail'
}
# Usage
result = check_wcag_compliance('#000000', '#FFFFFF', 'AA', False)
print(f"Contrast ratio: {result['ratio']}:1") # 21:1
print(f"WCAG {result['level']}: {result['grade']}") # PassFocus Management
Focus Management
class FocusManager {
private focusableSelectors = [
"a[href]",
"button:not([disabled])",
"textarea:not([disabled])",
"input:not([disabled])",
"select:not([disabled])",
'[tabindex]:not([tabindex="-1"])',
].join(", ");
getFocusableElements(container: HTMLElement): HTMLElement[] {
return Array.from(
container.querySelectorAll(this.focusableSelectors),
) as HTMLElement[];
}
trapFocus(container: HTMLElement): () => void {
const focusable = this.getFocusableElements(container);
const firstFocusable = focusable[0];
const lastFocusable = focusable[focusable.length - 1];
const handleTabKey = (e: KeyboardEvent) => {
if (e.key !== "Tab") return;
if (e.shiftKey) {
if (document.activeElement === firstFocusable) {
lastFocusable.focus();
e.preventDefault();
}
} else {
if (document.activeElement === lastFocusable) {
firstFocusable.focus();
e.preventDefault();
}
}
};
container.addEventListener("keydown", handleTabKey);
return () => container.removeEventListener("keydown", handleTabKey);
}
}Keyboard Navigation Handler
Keyboard Navigation Handler
// Keyboard navigation utilities
export const KeyboardNavigation = {
// Handle arrow key navigation in lists
handleListNavigation: (event: KeyboardEvent, items: HTMLElement[]) => {
const currentIndex = items.findIndex(
(item) => item === document.activeElement,
);
let nextIndex: number;
switch (event.key) {
case "ArrowDown":
event.preventDefault();
nextIndex = Math.min(currentIndex + 1, items.length - 1);
items[nextIndex]?.focus();
break;
case "ArrowUp":
event.preventDefault();
nextIndex = Math.max(currentIndex - 1, 0);
items[nextIndex]?.focus();
break;
case "Home":
event.preventDefault();
items[0]?.focus();
break;
case "End":
event.preventDefault();
items[items.length - 1]?.focus();
break;
}
},
// Make element keyboard accessible
makeAccessible: (element: HTMLElement, onClick: () => void): void => {
element.setAttribute("tabindex", "0");
element.setAttribute("role", "button");
element.addEventListener("keydown", (e) => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
onClick();
}
});
},
};React Component with Accessibility
React Component with Accessibility
import React, { useRef, useEffect, useState } from 'react';
interface ModalProps {
isOpen: boolean;
onClose: () => void;
title: string;
children: React.ReactNode;
}
const AccessibleModal: React.FC<ModalProps> = ({
isOpen,
onClose,
title,
children
}) => {
const modalRef = useRef<HTMLDivElement>(null);
const previousFocusRef = useRef<HTMLElement | null>(null);
useEffect(() => {
if (isOpen) {
// Save previous focus
previousFocusRef.current = document.activeElement as HTMLElement;
// Focus modal
modalRef.current?.focus();
// Trap focus within modal
const trapFocus = (e: KeyboardEvent) => {
if (e.key === 'Escape') {
onClose();
}
};
document.addEventListener('keydown', trapFocus);
return () => {
document.removeEventListener('keydown', trapFocus);
// Restore previous focus
previousFocusRef.current?.focus();
};
}
}, [isOpen, onClose]);
if (!isOpen) return null;
return (
<div
role="dialog"
aria-modal="true"
aria-labelledby="modal-title"
ref={modalRef}
tabIndex={-1}
className="modal-overlay"
onClick={onClose}
>
<div
className="modal-content"
onClick={(e) => e.stopPropagation()}
>
<h2 id="modal-title">{title}</h2>
<button
onClick={onClose}
aria-label="Close modal"
className="close-button"
>
×
</button>
<div className="modal-body">
{children}
</div>
</div>
</div>
);
};
export default AccessibleModal;Screen Reader Announcements
Screen Reader Announcements
class ScreenReaderAnnouncer {
private liveRegion: HTMLElement;
constructor() {
this.liveRegion = this.createLiveRegion();
}
private createLiveRegion(): HTMLElement {
const region = document.createElement("div");
region.setAttribute("role", "status");
region.setAttribute("aria-live", "polite");
region.setAttribute("aria-atomic", "true");
region.className = "sr-only";
region.style.cssText = `
position: absolute;
left: -10000px;
width: 1px;
height: 1px;
overflow: hidden;
`;
document.body.appendChild(region);
return region;
}
announce(message: string, priority: "polite" | "assertive" = "polite"): void {
this.liveRegion.setAttribute("aria-live", priority);
// Clear then set message to ensure announcement
this.liveRegion.textContent = "";
setTimeout(() => {
this.liveRegion.textContent = message;
}, 100);
}
cleanup(): void {
this.liveRegion.remove();
}
}
// Usage
const announcer = new ScreenReaderAnnouncer();
// Announce form validation error
announcer.announce("Email field is required", "assertive");
// Announce successful action
announcer.announce("Item added to cart", "polite");Semantic HTML with ARIA
Semantic HTML with ARIA
<!-- Bad: Non-semantic markup -->
<div class="button" onclick="submit()">Submit</div>
<!-- Good: Semantic HTML -->
<button type="submit" aria-label="Submit form">Submit</button>
<!-- Custom components with proper ARIA -->
<div
role="button"
tabindex="0"
aria-pressed="false"
onclick="toggle()"
onkeydown="handleKeyPress(event)"
>
Toggle Feature
</div>
<!-- Form with proper labels and error handling -->
<form>
<label for="email">Email Address</label>
<input
id="email"
type="email"
name="email"
aria-required="true"
aria-invalid="false"
aria-describedby="email-error"
/>
<span id="email-error" role="alert" aria-live="polite"></span>
</form>// Component: [Name]
// TODO: Customize for your framework (React, Vue, Svelte, etc.)
import React from 'react';
interface Props {
// TODO: Define props
}
export function ComponentName({ }: Props) {
// TODO: Add state and effects
return (
<div>
{/* TODO: Add component markup */}
</div>
);
}
Related skills
How it compares
Pick accessibility-compliance over generic lint rules when you need component-level WCAG remediation patterns and screen reader workflows, not just axe CI gates.
FAQ
Which WCAG versions does accessibility-compliance cover?
accessibility-compliance implements WCAG 2.1 and WCAG 2.2 patterns targeting AA compliance with guidance toward AAA, including contrast, keyboard access, and screen reader support.
How many reference guides ship with accessibility-compliance?
accessibility-compliance includes 6 reference guides covering semantic HTML with ARIA, React components, keyboard navigation, color contrast, screen reader announcements, and focus management.
When should accessibility-compliance run in a release cycle?
accessibility-compliance fits pre-ship design review and release audits when public-facing pages need WCAG remediation for contrast, labels, keyboard paths, and focus order.