jeninh

frontend-accessibility

0
0
# Install this skill:
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

  1. Semantic HTML first: Use <button>, <nav>, <main>, <form> - not divs with roles
  2. Keyboard accessible: Everything clickable must be focusable and operable with Enter/Space
  3. Screen reader context: Labels, alt text, and heading hierarchy convey structure without vision
  4. 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.

<!-- 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.

  1. Missing form labels - Every input needs <label for="...">
  2. Empty alt on informative images - alt="" marks image as decorative
  3. Div/span as buttons - Use <button>, not <div onclick>
  4. Missing skip link - Add "Skip to main content" for keyboard users
  5. Low color contrast - 4.5:1 for normal text, 3:1 for large text
  6. Keyboard traps - Focus must be able to leave modals/menus
  7. Missing focus indicators - Never outline: none without 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

  • htmlFor instead of for
  • className instead of class
  • 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.