Implement web accessibility (a11y) standards following WCAG 2.1 guidelines. Use when building accessible UIs, fixing accessibility issues, or ensuring compliance with disability standards. Handles ARIA attributes, keyboard navigation, screen readers, semantic HTML, and accessibility testing.
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Une commande directe contourne le prompt de vérification. Examinez la source avant de l'exécuter.
Implement web accessibility (a11y) standards following WCAG 2.1 guidelines. Use when building accessible UIs, fixing accessibility issues, or ensuring compliance with disability standards. Handles ARIA attributes, keyboard navigation, screen readers, semantic HTML, and accessibility testing.
Make a React modal component accessible:
- Framework: React + TypeScript
- WCAG Level: AA
- Requirements:
- Focus trap (focus stays inside the modal)
- Close with ESC key
- Close by clicking the background
- Title/description read by screen readers
Instructions
Step 1: Use Semantic HTML
Use meaningful HTML elements to make the structure clear.
Tasks:
Use semantic tags: <button>, <nav>, <main>, <header>, <footer>, etc.
Avoid overusing <div> and <span>
Use heading hierarchy (<h1> ~ <h6>) correctly
Connect <label> with <input>
Example (❌ Bad vs ✅ Good):
<!-- ❌ Bad example: using only div and span --><divclass="header"><spanclass="title">My App</span><divclass="nav"><divclass="nav-item"onclick="navigate()">Home</div><divclass="nav-item"onclick="navigate()">About</div></div></div><!-- ✅ Good example: semantic HTML --><header><h1>My App</h1><navaria-label="Main navigation"><ul><li><ahref="/">Home</a></li><li><ahref="/about">About</a></li></ul></nav></header>
Form Example:
<!-- ❌ Bad example: no label --><inputtype="text"placeholder="Enter your name"><!-- ✅ Good example: label connected --><labelfor="name">Name:</label><inputtype="text"id="name"name="name"required><!-- Or wrap with label --><label>
Email:
<inputtype="email"name="email"required></label>
Step 2: Implement Keyboard Navigation
Ensure all features are usable without a mouse.
Tasks:
Move focus with Tab and Shift+Tab
Activate buttons with Enter/Space
Navigate lists/menus with arrow keys
Close modals/dropdowns with ESC
Use tabindex appropriately
Decision Criteria:
Interactive elements → tabindex="0" (focusable)
Exclude from focus order → tabindex="-1" (programmatic focus only)
Do not change focus order → avoid using tabindex="1+"
## Accessibility Checklist### Semantic HTML- [x] Use semantic HTML tags (`<button>`, `<nav>`, `<main>`, etc.)
- [x] Heading hierarchy is correct (h1 → h2 → h3)
- [x] All form labels are connected
### Keyboard Navigation- [x] All interactive elements accessible via Tab
- [x] Buttons activated with Enter/Space
- [x] Modals/dropdowns closed with ESC
- [x] Focus indicator is clear (outline)
### ARIA- [x] `role` used appropriately
- [x] `aria-label` or `aria-labelledby` provided
- [x] `aria-live` used for dynamic content
- [x] Decorative elements use `aria-hidden="true"`### Visual- [x] Color contrast meets WCAG AA (4.5:1)
- [x] Information not conveyed by color alone
- [x] Text size can be adjusted
- [x] Responsive design
### Testing- [x] 0 axe DevTools violations
- [x] Lighthouse Accessibility score 90+
- [x] Keyboard test passed
- [x] Screen reader test completed
Constraints
Mandatory Rules (MUST)
Keyboard Accessibility: All features must be usable without a mouse
Support Tab, Enter, Space, arrow keys, and ESC
Implement focus trap (for modals)
Alternative Text: All images must have an alt attribute
Meaningful images: descriptive alt text
Decorative images: alt="" (screen reader ignores)
Clear Labels: All form inputs must have an associated label
<label for="..."> or aria-label
Do not use placeholder alone as a substitute for a label
Prohibited Actions (MUST NOT)
Do Not Remove Outline: Never use outline: none
Disastrous for keyboard users
Must provide a custom focus style instead
Do Not Use tabindex > 0: Avoid changing focus order
Keep DOM order logical
Exception: only when there is a special reason
Do Not Convey Information by Color Alone: Accompany with icons or text
Consider users with color blindness
e.g., "Click red item" → "Click ⚠️ Error item"
Examples
Example 1: Accessible Form
functionAccessibleContactForm() {
const [errors, setErrors] = useState<Record<string, string>>({});
const [submitStatus, setSubmitStatus] = useState<'idle' | 'success' | 'error'>('idle');
return (
<formonSubmit={handleSubmit}noValidate><h2id="form-title">Contact Us</h2><pid="form-description">Please fill out the form below to get in touch.</p>
{/* Name */}
<divclassName="form-group"><labelhtmlFor="name">
Name <spanaria-label="required">*</span></label><inputtype="text"id="name"name="name"requiredaria-required="true"aria-invalid={!!errors.name}aria-describedby={errors.name ? 'name-error' :undefined}
/>
{errors.name && (
<spanid="name-error"role="alert"className="error">
{errors.name}
</span>
)}
</div>
{/* Email */}
<divclassName="form-group"><labelhtmlFor="email">
Email <spanaria-label="required">*</span></label><inputtype="email"id="email"name="email"requiredaria-required="true"aria-invalid={!!errors.email}aria-describedby={errors.email ? 'email-error' : 'email-hint'}
/><spanid="email-hint"className="hint">
We'll never share your email.
</span>
{errors.email && (
<spanid="email-error"role="alert"className="error">
{errors.email}
</span>
)}
</div>
{/* Submit button */}
<buttontype="submit"disabled={submitStatus === 'loading'}>
{submitStatus === 'loading' ? 'Submitting...' : 'Submit'}
</button>
{/* Success/failure messages */}
{submitStatus === 'success' && (
<divrole="alert"aria-live="polite"className="success">
✅ Form submitted successfully!
</div>
)}
{submitStatus === 'error' && (
<divrole="alert"aria-live="assertive"className="error">
⚠️ An error occurred. Please try again.
</div>
)}
</form>
);
}