
Web Accessibility
- 422 installs
- 262 repo stars
- Updated July 11, 2026
- hoodini/ai-agents-skills
web-accessibility is an agent skill that audits and fixes web UIs for WCAG 2.1 compliance covering semantic HTML, ARIA, keyboard navigation, contrast, and screen-reader support for developers shipping accessible frontend
About
web-accessibility is an agent skill from hoodini/ai-agents-skills that guides building accessible web applications following WCAG 2.1 guidelines. It activates on triggers like accessibility, a11y, WCAG, ARIA, screen reader, and keyboard navigation. The skill documents concrete React/TSX patterns for buttons with aria-pressed and aria-disabled, modal dialogs with role=dialog and aria-modal, and other ARIA roles agents should apply during implementation or review. Coverage spans semantic HTML structure, keyboard focus order, color contrast checks, and screen-reader labeling before release. Developers reach for web-accessibility inside Claude Code or Cursor when shipping customer-facing SPAs or design-system components and need agents to catch missing labels, trap focus in modals, or replace div-click handlers with proper interactive elements. The skill complements automated linters by encoding WCAG-oriented fix patterns agents can apply directly in component files.
- WCAG compliance checks
- Semantic HTML fixes
- Keyboard and focus order
- ARIA and screen readers
- Color contrast validation
Web Accessibility by the numbers
- 422 all-time installs (skills.sh)
- +9 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #652 of 2,245 Frontend Development skills by installs in the Skillselion catalog
- Data as of Aug 2, 2026 (Skillselion catalog sync)
npx skills add https://github.com/hoodini/ai-agents-skills --skill web-accessibilityAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 422 |
|---|---|
| repo stars | ★ 262 |
| Last updated | July 11, 2026 |
| Repository | hoodini/ai-agents-skills ↗ |
How do you fix WCAG accessibility issues in React?
Audit and fix web UIs for WCAG accessibility—semantic HTML, keyboard navigation, ARIA, contrast, and screen-reader support before release.
Who is it for?
Frontend developers shipping React or TSX apps who need agent-guided WCAG 2.1 fixes for ARIA, keyboard navigation, and screen-reader support before release.
Skip if: Native mobile accessibility (iOS VoiceOver or Android TalkBack-only projects) or backend API work with no UI surface.
When should I use this skill?
User mentions accessibility, a11y, WCAG, ARIA, keyboard navigation, screen reader support, or asks to audit UI compliance before shipping.
What you get
Accessible component patches with semantic HTML, ARIA roles, keyboard navigation, and screen-reader labels meeting WCAG 2.1 patterns.
- Accessible component patches
- ARIA attribute corrections
- Keyboard navigation fixes
By the numbers
- Targets WCAG 2.1 accessibility guidelines
- Documents ARIA patterns for buttons and modal dialogs in TSX examples
Files
Web Accessibility (WCAG 2.1)
Build accessible web applications that work for everyone.
ARIA Patterns
Button
<button
type="button"
aria-pressed={isPressed}
aria-disabled={isDisabled}
onClick={handleClick}
>
Toggle Feature
</button>Modal Dialog
<div
role="dialog"
aria-modal="true"
aria-labelledby="modal-title"
aria-describedby="modal-description"
>
<h2 id="modal-title">Confirm Action</h2>
<p id="modal-description">Are you sure you want to proceed?</p>
<button onClick={onConfirm}>Confirm</button>
<button onClick={onCancel}>Cancel</button>
</div>Navigation Menu
<nav aria-label="Main navigation">
<ul role="menubar">
<li role="none">
<a role="menuitem" href="/home">Home</a>
</li>
<li role="none">
<button
role="menuitem"
aria-haspopup="true"
aria-expanded={isOpen}
>
Products
</button>
{isOpen && (
<ul role="menu" aria-label="Products submenu">
<li role="none">
<a role="menuitem" href="/products/new">New</a>
</li>
</ul>
)}
</li>
</ul>
</nav>Keyboard Navigation
Focus Management
import { useEffect, useRef } from 'react';
function Modal({ isOpen, onClose, children }) {
const modalRef = useRef<HTMLDivElement>(null);
const previousFocus = useRef<HTMLElement | null>(null);
useEffect(() => {
if (isOpen) {
previousFocus.current = document.activeElement as HTMLElement;
modalRef.current?.focus();
} else {
previousFocus.current?.focus();
}
}, [isOpen]);
// Trap focus within modal
const handleKeyDown = (e: React.KeyboardEvent) => {
if (e.key === 'Escape') {
onClose();
}
if (e.key === 'Tab') {
const focusable = modalRef.current?.querySelectorAll(
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
);
if (focusable && focusable.length > 0) {
const first = focusable[0] as HTMLElement;
const last = focusable[focusable.length - 1] as HTMLElement;
if (e.shiftKey && document.activeElement === first) {
e.preventDefault();
last.focus();
} else if (!e.shiftKey && document.activeElement === last) {
e.preventDefault();
first.focus();
}
}
}
};
if (!isOpen) return null;
return (
<div
ref={modalRef}
role="dialog"
aria-modal="true"
tabIndex={-1}
onKeyDown={handleKeyDown}
>
{children}
</div>
);
}Color Contrast
Minimum contrast ratios (WCAG AA):
- Normal text: 4.5:1
- Large text (18pt+): 3:1
- UI components: 3:1
function getContrastRatio(color1: string, color2: string): number {
const lum1 = getLuminance(color1);
const lum2 = getLuminance(color2);
const lighter = Math.max(lum1, lum2);
const darker = Math.min(lum1, lum2);
return (lighter + 0.05) / (darker + 0.05);
}
function getLuminance(hex: string): number {
const rgb = hexToRgb(hex);
const [r, g, b] = rgb.map((c) => {
c = c / 255;
return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
});
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
}Accessible Forms
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="email">
Email address
<span aria-hidden="true">*</span>
<span className="sr-only">(required)</span>
</label>
<input
id="email"
type="email"
aria-required="true"
aria-invalid={errors.email ? 'true' : 'false'}
aria-describedby={errors.email ? 'email-error' : undefined}
/>
{errors.email && (
<p id="email-error" role="alert" className="error">
{errors.email}
</p>
)}
</div>
<button type="submit">Submit</button>
</form>Screen Reader Only Content
.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;
}Testing
# Automated testing
npm install -D axe-core @axe-core/react
# In tests
import { axe, toHaveNoViolations } from 'jest-axe';
expect.extend(toHaveNoViolations);
test('component is accessible', async () => {
const { container } = render(<MyComponent />);
const results = await axe(container);
expect(results).toHaveNoViolations();
});Resources
- WCAG 2.1 Guidelines: https://www.w3.org/WAI/WCAG21/quickref/
- ARIA Authoring Practices: https://www.w3.org/WAI/ARIA/apg/
Related skills
How it compares
Use web-accessibility for WCAG-oriented component fixes during development; pair with dedicated a11y-debugging browser tools when you need runtime axe audits on a live page.
FAQ
Which WCAG version does web-accessibility target?
web-accessibility targets WCAG 2.1 guidelines and encodes React TSX examples for semantic HTML, ARIA attributes, keyboard navigation, and screen-reader-compatible labeling.
What ARIA patterns does web-accessibility include?
web-accessibility documents button patterns with aria-pressed and aria-disabled plus modal dialogs using role=dialog, aria-modal=true, aria-labelledby, and aria-describedby attributes.
When should agents activate web-accessibility?
Agents should activate web-accessibility when users mention accessibility, a11y, WCAG, ARIA, screen readers, or keyboard navigation during frontend implementation or pre-release UI review.