Use this skill when the user writes/edits components, asks to "fix accessibility issues", "add ARIA labels", "improve accessibility", "check WCAG compliance", "remediate a11y violations", mentions "screen reader support", "keyboard navigation", or wants AI-powered accessibility fixes with one-click application. Automatically analyzes components for a11y issues and suggests context-aware fixes. Trigger on PostToolUse hook or explicit request.
/plugin marketplace add flight505/storybook-assistant-plugin/plugin install flight505-storybook-assistant@flight505/storybook-assistant-pluginThis skill inherits all available tools. When active, it can use any tool Claude has access to.
examples/fix-patterns.mdreferences/wcag-rules.mdscripts/analyze_component.pyscripts/generate_fixes.pyAutomatically detect and fix accessibility issues in components with AI-powered analysis, context-aware fix suggestions, and one-click application. Goes beyond detection to provide ranked remediation options based on WCAG 2.2 best practices.
This skill transforms accessibility from a manual checklist into an automated workflow with intelligent fix suggestions.
Automatically check components for WCAG 2.2 violations:
AI understands component purpose and suggests appropriate fixes:
Apply fixes instantly without manual implementation:
Built-in support for latest accessibility standards:
When you create or edit a component, the accessibility-auditor agent automatically:
You can also explicitly request accessibility analysis:
User: "Check this Button component for accessibility issues"
Claude: [Runs accessibility-auditor agent]
User: "Fix the accessibility violations in Modal.tsx"
Claude: [Analyzes, suggests fixes, applies selected fix]
Problem: Buttons, links, or inputs without labels
Examples:
// ❌ Bad: Button has no accessible name
<button onClick={handleClose}>×</button>
// ✅ Fix Option 1: Visible text with icon (BEST)
<button onClick={handleClose}>
<span aria-hidden="true">×</span>
<span className="sr-only">Close dialog</span>
</button>
// ✅ Fix Option 2: aria-label (GOOD)
<button onClick={handleClose} aria-label="Close dialog">×</button>
// ✅ Fix Option 3: title attribute (ACCEPTABLE)
<button onClick={handleClose} title="Close dialog">×</button>
AI Suggestion:
Context: Close button in modal header
Recommendation: Option 1 (best for all users - visible + announced)
WCAG: 4.1.2 Name, Role, Value (Level A)
Problem: Text/UI elements don't meet WCAG contrast ratios
Examples:
// ❌ Bad: Contrast ratio 2.1:1 (fails WCAG AA)
<button style={{ color: '#999', background: '#fff' }}>Submit</button>
// ✅ Fix: Contrast ratio 4.6:1 (passes AA)
<button style={{ color: '#666', background: '#fff' }}>Submit</button>
// ✅ Better: Contrast ratio 7.2:1 (passes AAA)
<button style={{ color: '#333', background: '#fff' }}>Submit</button>
AI Suggestion:
Issue: Text color #999 on white background (2.1:1 - fails)
Required: 4.5:1 for normal text (WCAG AA)
Suggested colors:
- #666 (4.6:1) ✓ WCAG AA
- #555 (5.8:1) ✓ WCAG AA
- #333 (7.2:1) ✓ WCAG AAA
WCAG: 1.4.3 Contrast (Minimum) (Level AA)
Problem: Form inputs without associated labels
Examples:
// ❌ Bad: No label association
<input type="email" placeholder="Email" />
// ✅ Fix Option 1: Proper label element (BEST)
<label htmlFor="email">
Email address
<input id="email" type="email" placeholder="you@example.com" />
</label>
// ✅ Fix Option 2: Label with nesting (GOOD)
<label>
Email address
<input type="email" placeholder="you@example.com" />
</label>
// ✅ Fix Option 3: aria-label (ACCEPTABLE)
<input type="email" aria-label="Email address" placeholder="Email" />
AI Suggestion:
Context: Email input in login form
Recommendation: Option 1 (explicit label with htmlFor - most robust)
WCAG: 3.3.2 Labels or Instructions (Level A)
Problem: Interactive elements lack visible focus state
Examples:
// ❌ Bad: Focus outline removed
<button style={{ outline: 'none' }} onClick={handleClick}>
Click me
</button>
// ✅ Fix Option 1: Custom focus-visible (BEST)
<button
className="focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2"
onClick={handleClick}
>
Click me
</button>
// ✅ Fix Option 2: Custom outline (GOOD)
<button
style={{ outline: 'none' }}
className="focus:outline-blue focus:outline-2 focus:outline-offset-2"
onClick={handleClick}
>
Click me
</button>
// ✅ Fix Option 3: Default outline (ACCEPTABLE)
<button onClick={handleClick}>Click me</button>
AI Suggestion:
Issue: outline: none removes focus indicator
Solution: Use :focus-visible for keyboard-only focus styling
WCAG: 2.4.7 Focus Visible (Level AA)
Problem: Incorrect or redundant ARIA attributes
Examples:
// ❌ Bad: Redundant role on button
<button role="button" onClick={handleClick}>Submit</button>
// ✅ Fix: Remove redundant role (native button already has role)
<button onClick={handleClick}>Submit</button>
// ❌ Bad: Invalid ARIA attribute
<div role="button" onClick={handleClick}>Click</div>
// ✅ Fix: Use semantic button element (BEST)
<button onClick={handleClick}>Click</button>
// ✅ Fix: Add keyboard support if div required (ACCEPTABLE)
<div
role="button"
onClick={handleClick}
onKeyDown={(e) => e.key === 'Enter' && handleClick()}
tabIndex={0}
>
Click
</div>
AI Suggestion:
Issue: Redundant role="button" on <button> element
Solution: Remove role attribute (native HTML provides this)
WCAG: 4.1.2 Name, Role, Value (Level A)
Problem: Images without alternative text
Examples:
// ❌ Bad: No alt attribute
<img src="/avatar.jpg" />
// ✅ Fix Option 1: Descriptive alt (BEST - informative images)
<img src="/avatar.jpg" alt="Profile photo of John Doe" />
// ✅ Fix Option 2: Empty alt (GOOD - decorative images)
<img src="/decorative-pattern.png" alt="" aria-hidden="true" />
// ✅ Fix Option 3: aria-label (ACCEPTABLE - when alt insufficient)
<img
src="/complex-chart.png"
alt="Sales data visualization"
aria-label="Bar chart showing 40% increase in Q4 sales"
/>
AI Suggestion:
Context: User avatar in profile card
Recommendation: Descriptive alt text with user name
WCAG: 1.1.1 Non-text Content (Level A)
// User creates Modal component
export function Modal({ isOpen, onClose, children }) {
if (!isOpen) return null;
return (
<div className="modal-overlay" onClick={onClose}>
<div className="modal-content">
<button onClick={onClose}>×</button>
{children}
</div>
</div>
);
}
AI Detection (Automatic):
❌ 4 accessibility issues detected in Modal.tsx
Issue 1: Missing accessible name (Line 7)
Element: <button>×</button>
WCAG: 4.1.2 Name, Role, Value (Level A)
Fix options:
[1] Add sr-only text: <button><span aria-hidden>×</span><span class="sr-only">Close</span></button>
[2] Add aria-label: <button aria-label="Close modal">×</button>
[3] Add title: <button title="Close">×</button>
Issue 2: Missing ARIA role (Line 5)
Element: <div className="modal-overlay">
WCAG: 4.1.2 Name, Role, Value (Level A)
Fix: Add role="dialog" and aria-modal="true"
Issue 3: Missing focus trap (Line 6)
Element: Modal content
WCAG: 2.4.3 Focus Order (Level A)
Fix: Implement focus trap to prevent tabbing out of modal
Issue 4: No Escape key handler (Line 5)
Element: Modal
WCAG: 2.1.2 No Keyboard Trap (Level A)
Fix: Add onKeyDown handler for Escape key
Apply fixes? [All] [Select] [Custom] [Skip]
User selects: "All"
AI applies fixes:
import { useEffect, useRef } from 'react';
import { FocusTrap } from './FocusTrap';
export function Modal({ isOpen, onClose, children }) {
const modalRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (!isOpen) return;
const handleEscape = (e: KeyboardEvent) => {
if (e.key === 'Escape') onClose();
};
document.addEventListener('keydown', handleEscape);
modalRef.current?.focus();
return () => document.removeEventListener('keydown', handleEscape);
}, [isOpen, onClose]);
if (!isOpen) return null;
return (
<div
className="modal-overlay"
onClick={onClose}
aria-hidden={!isOpen}
>
<FocusTrap>
<div
ref={modalRef}
className="modal-content"
role="dialog"
aria-modal="true"
tabIndex={-1}
onClick={(e) => e.stopPropagation()}
>
<button
onClick={onClose}
aria-label="Close modal"
>
<span aria-hidden="true">×</span>
<span className="sr-only">Close</span>
</button>
{children}
</div>
</FocusTrap>
</div>
);
}
Verification:
✓ All issues resolved
✓ Modal now passes WCAG 2.2 Level AA
✓ Added focus trap component (FocusTrap.tsx)
✓ Added sr-only CSS utility
Run accessibility test? [Yes] [No]
This skill works seamlessly with the testing-suite skill:
Combined workflow:
1. Create component → AI detects issues → Apply fixes
2. Run tests → Verify with axe-core → Pass ✓
3. Create stories → Test keyboard navigation → Pass ✓
4. Commit → CI runs a11y tests → Deploy ✓
AI remembers your fix preferences:
You've chosen aria-label for icon buttons 5 times.
Default suggestion updated to rank aria-label first for icon buttons.
Fix multiple components at once:
User: "Fix all accessibility issues in src/components/"
Scanning 23 components...
✓ Button.tsx: 2 issues fixed
✓ Input.tsx: 3 issues fixed
✓ Modal.tsx: 4 issues fixed
⚠️ Dropdown.tsx: 1 issue requires custom fix
✓ Card.tsx: 1 issue fixed
21/23 components now pass WCAG AA
2 components need manual review
Define project-specific a11y rules:
# .storybook/a11y-config.yml
rules:
- id: 'custom-button-label'
description: 'All buttons must have aria-label or visible text'
severity: 'error'
fix: 'suggest-aria-label'
- id: 'custom-min-contrast'
description: 'Require WCAG AAA contrast (7:1) for all text'
severity: 'warning'
fix: 'suggest-darker-color'
This skill includes Python scripts for deep analysis:
Analyzes component AST for accessibility issues:
See: skills/accessibility-remediation/scripts/analyze_component.py
Generates context-aware fix suggestions:
See: skills/accessibility-remediation/scripts/generate_fixes.py
Complete reference of all WCAG 2.2 success criteria with:
See: skills/accessibility-remediation/references/wcag-rules.md
Library of proven fix patterns:
See: skills/accessibility-remediation/examples/fix-patterns.md
If AI suggests unnecessary fixes:
User: "This is a false positive - the component is decorative"
Claude: Understood. I'll:
1. Mark this pattern as acceptable
2. Update detection rules
3. Remember for future similar cases
Would you like to add this to .storybook/a11y-ignore.yml?
For components with complex accessibility needs:
User: "This datepicker needs custom keyboard navigation"
Claude: This component requires manual implementation:
1. Arrow keys for date navigation
2. Page Up/Down for month navigation
3. Home/End for week navigation
4. Escape to close
I can provide a reference implementation from accessible datepicker patterns.
Would you like me to generate a template?
Transform accessibility from manual checklist to automated workflow:
Result: Ship accessible components by default with 80% less effort.