SKILL.md

  1---
  2name: frontend-accessibility
  3description: 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.
  4user-invocable: true
  5license: LicenseRef-MutuaL-1.2
  6metadata:
  7  author: Amolith <amolith@secluded.site>
  8---
  9
 10Write accessible frontend code by default. Semantic HTML covers most needs; ARIA is for gaps HTML can't fill.
 11
 12## Core principles
 13
 141. **Semantic HTML first**: Use `<button>`, `<nav>`, `<main>`, `<form>` - not divs with roles
 152. **Keyboard accessible**: Everything clickable must be focusable and operable with Enter/Space
 163. **Screen reader context**: Labels, alt text, and heading hierarchy convey structure without vision
 174. **No ARIA is better than bad ARIA**: ARIA overrides native semantics and can make things _worse_
 18
 19## Quick reference
 20
 21### Images
 22
 23```html
 24<!-- Informative: describe content -->
 25<img src="chart.png" alt="Sales increased 25% from Q1 to Q2" />
 26
 27<!-- Decorative: empty alt -->
 28<img src="divider.png" alt="" />
 29
 30<!-- Complex: summarize + link to details -->
 31<img
 32	src="flowchart.png"
 33	alt="User registration flow. Details in following section."
 34/>
 35```
 36
 37### Interactive elements
 38
 39```html
 40<!-- Correct: semantic button -->
 41<button onclick="save()">Save</button>
 42
 43<!-- Wrong: div cosplaying as button -->
 44<div onclick="save()" role="button" tabindex="0">Save</div>
 45```
 46
 47The div requires `role`, `tabindex`, `onkeydown` for Enter/Space, focus styles, and still won't work with voice control. Use `<button>`.
 48
 49### Forms
 50
 51```html
 52<label for="email">Email address</label>
 53<input
 54	type="email"
 55	id="email"
 56	name="email"
 57	required
 58	aria-describedby="email-hint"
 59/>
 60<span id="email-hint">We'll never share your email</span>
 61```
 62
 63Every input needs a visible `<label>` with matching `for`/`id`. Use `aria-describedby` for hints, `aria-invalid` for errors.
 64
 65### Headings
 66
 67```html
 68<!-- One per page -->
 69<h1>Page title</h1>
 70<!-- Don't skip levels -->
 71<h2>Section</h2>
 72<h3>Subsection</h3>
 73<h2>Another section</h2>
 74```
 75
 76Headings create navigable structure. Screen reader users jump by heading level.
 77
 78### Links
 79
 80```html
 81<!-- Good: describes destination -->
 82<a href="/pricing">View pricing plans</a>
 83
 84<!-- Bad: meaningless out of context -->
 85<a href="/pricing">Click here</a>
 86```
 87
 88## When to use ARIA
 89
 90Use ARIA only when HTML has no semantic equivalent:
 91
 92| Need           | Solution                                    |
 93| -------------- | ------------------------------------------- |
 94| Button         | `<button>` not `role="button"`              |
 95| Navigation     | `<nav>` not `role="navigation"`             |
 96| Live updates   | `aria-live="polite"` (no HTML equivalent)   |
 97| Current page   | `aria-current="page"` (no HTML equivalent)  |
 98| Expanded state | `aria-expanded="true"` (no HTML equivalent) |
 99| Custom widget  | ARIA + keyboard handling (last resort)      |
100
101## Common violations to avoid
102
103See [antipatterns.md](references/antipatterns.md) for detailed examples.
104
1051. **Missing form labels** - Every input needs `<label for="...">`
1062. **Empty alt on informative images** - `alt=""` marks image as decorative
1073. **Div/span as buttons** - Use `<button>`, not `<div onclick>`
1084. **Missing skip link** - Add "Skip to main content" for keyboard users
1095. **Low color contrast** - 4.5:1 for normal text, 3:1 for large text
1106. **Keyboard traps** - Focus must be able to leave modals/menus
1117. **Missing focus indicators** - Never `outline: none` without replacement
112
113## Motion and animation
114
115Respect user preferences for reduced motion:
116
117```css
118/* Default: full animation */
119.animated {
120	transition: transform 0.3s ease;
121}
122
123/* Reduce or remove for users who prefer it */
124@media (prefers-reduced-motion: reduce) {
125	.animated {
126		transition: none;
127	}
128}
129```
130
131Or start safe and enhance:
132
133```css
134/* Safe default */
135.animated {
136	transition: none;
137}
138
139/* Only animate if user hasn't requested reduced motion */
140@media (prefers-reduced-motion: no-preference) {
141	.animated {
142		transition: transform 0.3s ease;
143	}
144}
145```
146
147Applies to: transitions, transforms, parallax, auto-playing video, animated illustrations. Essential for users with vestibular disorders.
148
149## Framework-specific notes
150
151### React/JSX
152
153- `htmlFor` instead of `for`
154- `className` instead of `class`
155- Fragments (`<>`) don't affect accessibility tree
156- Manage focus with refs when content changes dynamically
157
158### Component libraries
159
160If using Radix, Headless UI, or similar - they handle ARIA. Don't add redundant attributes.
161
162## Validation
163
164Generated code should pass:
165
166- **axe-core**: Catches ~57% of WCAG issues automatically
167- **Manual keyboard test**: Tab through everything, operate with Enter/Space
168- **Screen reader spot check**: VoiceOver (Mac), NVDA (Windows), Orca (Linux)
169
170Automated tools miss context-dependent issues (alt text quality, heading hierarchy logic, reading order). Human review still required.
171
172## Detailed patterns
173
174See [patterns.md](references/patterns.md) for:
175
176- Modal dialogs and focus management
177- Custom select/combobox
178- Tabs and tab panels
179- Accordions
180- Toast notifications
181- Data tables