Use when adding new error messages to React, or seeing "unknown error code" warnings.
npx skills add jeninh/ampskills-dotfile --skill "frontend-accessibility"
Install specific skill from multi-skill repository
# Description
Generates accessible HTML, React, and frontend code following WCAG 2.2 AA guidelines. Use when creating UI components, forms, navigation, or any user-facing frontend code. Focuses on semantic HTML, keyboard accessibility, and screen reader compatibility.
# SKILL.md
name: frontend-accessibility
description: Generates accessible HTML, React, and frontend code following WCAG 2.2 AA guidelines. Use when creating UI components, forms, navigation, or any user-facing frontend code. Focuses on semantic HTML, keyboard accessibility, and screen reader compatibility.
license: AGPL-3.0-or-later
metadata:
author: Amolith [email protected]
Write accessible frontend code by default. Semantic HTML covers most needs; ARIA is for gaps HTML can't fill.
Core principles
- Semantic HTML first: Use
<button>,<nav>,<main>,<form>- not divs with roles - Keyboard accessible: Everything clickable must be focusable and operable with Enter/Space
- Screen reader context: Labels, alt text, and heading hierarchy convey structure without vision
- No ARIA is better than bad ARIA: ARIA overrides native semantics and can make things worse
Quick reference
Images
<!-- Informative: describe content -->
<img src="chart.png" alt="Sales increased 25% from Q1 to Q2">
<!-- Decorative: empty alt -->
<img src="divider.png" alt="">
<!-- Complex: summarize + link to details -->
<img src="flowchart.png" alt="User registration flow. Details in following section.">
Interactive elements
<!-- Correct: semantic button -->
<button onclick="save()">Save</button>
<!-- Wrong: div cosplaying as button -->
<div onclick="save()" role="button" tabindex="0">Save</div>
The div requires role, tabindex, onkeydown for Enter/Space, focus styles, and still won't work with voice control. Use <button>.
Forms
<label for="email">Email address</label>
<input type="email" id="email" name="email" required aria-describedby="email-hint">
<span id="email-hint">We'll never share your email</span>
Every input needs a visible <label> with matching for/id. Use aria-describedby for hints, aria-invalid for errors.
Headings
<h1>Page title</h1> <!-- One per page -->
<h2>Section</h2> <!-- Don't skip levels -->
<h3>Subsection</h3>
<h2>Another section</h2>
Headings create navigable structure. Screen reader users jump by heading level.
Links
<!-- Good: describes destination -->
<a href="/pricing">View pricing plans</a>
<!-- Bad: meaningless out of context -->
<a href="/pricing">Click here</a>
When to use ARIA
Use ARIA only when HTML has no semantic equivalent:
| Need | Solution |
|---|---|
| Button | <button> not role="button" |
| Navigation | <nav> not role="navigation" |
| Live updates | aria-live="polite" (no HTML equivalent) |
| Current page | aria-current="page" (no HTML equivalent) |
| Expanded state | aria-expanded="true" (no HTML equivalent) |
| Custom widget | ARIA + keyboard handling (last resort) |
Common violations to avoid
See antipatterns.md for detailed examples.
- Missing form labels - Every input needs
<label for="..."> - Empty alt on informative images -
alt=""marks image as decorative - Div/span as buttons - Use
<button>, not<div onclick> - Missing skip link - Add "Skip to main content" for keyboard users
- Low color contrast - 4.5:1 for normal text, 3:1 for large text
- Keyboard traps - Focus must be able to leave modals/menus
- Missing focus indicators - Never
outline: nonewithout replacement
Motion and animation
Respect user preferences for reduced motion:
/* Default: full animation */
.animated {
transition: transform 0.3s ease;
}
/* Reduce or remove for users who prefer it */
@media (prefers-reduced-motion: reduce) {
.animated {
transition: none;
}
}
Or start safe and enhance:
/* Safe default */
.animated {
transition: none;
}
/* Only animate if user hasn't requested reduced motion */
@media (prefers-reduced-motion: no-preference) {
.animated {
transition: transform 0.3s ease;
}
}
Applies to: transitions, transforms, parallax, auto-playing video, animated illustrations. Essential for users with vestibular disorders.
Framework-specific notes
React/JSX
htmlForinstead offorclassNameinstead ofclass- Fragments (
<>) don't affect accessibility tree - Manage focus with refs when content changes dynamically
Component libraries
If using Radix, Headless UI, or similar - they handle ARIA. Don't add redundant attributes.
Validation
Generated code should pass:
- axe-core: Catches ~57% of WCAG issues automatically
- Manual keyboard test: Tab through everything, operate with Enter/Space
- Screen reader spot check: VoiceOver (Mac), NVDA (Windows), Orca (Linux)
Automated tools miss context-dependent issues (alt text quality, heading hierarchy logic, reading order). Human review still required.
Detailed patterns
See patterns.md for:
- Modal dialogs and focus management
- Custom select/combobox
- Tabs and tab panels
- Accordions
- Toast notifications
- Data tables
# Supported AI Coding Agents
This skill is compatible with the SKILL.md standard and works with all major AI coding agents:
Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.