agentsclimarketplace

A11y

Skill Surfrrosa/claude-skills/a11y

Free Claude Code audit toolkit: accessibility, performance, SEO, privacy, design, deploy safety, codebase audits. 14 slash commands, MIT licensed.

Install
npx -y skills add Surfrrosa/claude-skills --skill a11y

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Audit accessibility (WCAG) compliance in source code and optionally against live URLs

SKILL.md

14.9 KB, as published. Nobody here has run it

Accessibility Audit

Scan a project's source code for WCAG 2.1 accessibility violations. Optionally check live URLs for rendered accessibility issues. Can auto-fix safe categories.

Sample output

A successful run produces something like:

## Accessibility Audit — marketing-site
Score: 76/100 (C)
Stack: Next.js 16

### CRITICAL (blocks entire user groups)
1. Keyboard accessibility — src/components/NavMenu.tsx:42 — onClick handler on <div> with no tabIndex or onKeyDown. Keyboard users can't open the menu. Fix: change to <button>.

### SERIOUS
1. Forms — src/app/contact/page.tsx:18 — <input name="email"> has placeholder but no <label>. Fix: wrap in <label> or add aria-label.
2. Images — src/components/Hero.tsx:24 — <img src="/hero.jpg"> missing alt attribute.

### MODERATE
1. Heading hierarchy — src/app/about/page.tsx — page jumps from h1 to h3, skipping h2.

### Summary
- 1 critical, 2 serious, 1 moderate
- Top priority: NavMenu keyboard accessibility (blocks every keyboard user)

Arguments

The user may specify:

  • No args: audit current working directory
  • A project name or path (e.g., myapp, marketing-site)
  • --fix: auto-fix safe categories (missing alt placeholders, missing ARIA labels on obvious elements, lang attribute, etc.)
  • --live: also fetch live URLs and audit the rendered HTML
  • --scope <path>: limit to a specific directory or file

Parse the argument string. Examples:

  • /a11y -- audit current project, source only
  • /a11y myapp -- audit myapp source
  • /a11y myapp --live -- audit myapp source + live URL
  • /a11y --fix -- audit and auto-fix current project
  • /a11y --scope src/components -- audit only components directory

Project Registry

AliasPathLive URL
myapp(add your projects here)(add your projects here)

Process

Step 0: Detect the project

  1. Resolve path from alias table or cwd
  2. Detect the stack (Next.js, Astro, Flask/Jinja, static HTML, React Native)
  3. Identify template/component directories where HTML is generated:
    • Next.js: app/, src/app/, src/components/, components/
    • Astro: src/pages/, src/layouts/, src/components/
    • Flask/Jinja: src/templates/, templates/, src/**/templates/
    • Static HTML: all .html files in root and subdirectories
    • React Native / Expo: skip this audit entirely -- native apps use a different accessibility model (accessibilityLabel, accessibilityRole, etc.). Note this and suggest a native-specific check instead.
  4. Read CLAUDE.md for any project-specific accessibility notes or conventions

Step 1: Structural / Semantic HTML

1a. Landmark regions

Search layouts and page templates for:

  • Does the page have a <main> element? (exactly one per page)
  • Does the page have a <nav> element for primary navigation?
  • If there are multiple <nav> elements, does each have an aria-label or aria-labelledby to distinguish them?
  • Is there a <header> and <footer> at the page level?
  • Are <section> elements used with headings or aria-label (a <section> without an accessible name is meaningless to screen readers)?

Flag: Missing <main>, navigation without labels when multiple exist, <section> without accessible name.

1b. Heading hierarchy

For each page/template:

  • Is there exactly one <h1>?
  • Do headings follow a logical order (no skipping from h1 to h3)?
  • Are headings used for structure, not just styling? (A <h3> used because it "looks right" instead of using CSS is a smell)

Flag: Missing h1, skipped heading levels, multiple h1s on a single page.

1c. Lists

  • Are groups of related links wrapped in <ul> or <ol>, not just stacked <a> tags with <br> between them?
  • Are navigation menus using list markup?

Flag: Navigation links not in list elements.

Step 2: Interactive Elements

2a. Keyboard accessibility

Search all components/templates for interactive elements:

  • Click handlers on non-interactive elements: onClick / @click / on:click on <div>, <span>, <td>, <img>, or other non-interactive elements without role and tabIndex. These are invisible to keyboard users.
  • Missing keyboard equivalents: onClick without corresponding onKeyDown / onKeyUp handler on non-button/non-link elements.
  • Positive tabindex: tabindex values greater than 0 break natural tab order. tabindex="0" (add to tab order) and tabindex="-1" (programmatic focus only) are fine.
  • Autofocus abuse: autoFocus on elements that aren't the primary action on the page (disorienting for screen reader users).

Flag: Click handlers on divs/spans without role+tabIndex, positive tabindex values.

2b. Buttons and links

  • <a> tags without href (or with href="#" or href="javascript:void(0)") -- these should be <button> elements.
  • <button> elements without visible text or aria-label. Icon-only buttons need labels.
  • Links that open in new tabs (target="_blank") without indicating this to the user (add aria-label suffix or visible indicator). Also check for rel="noopener".
  • Empty links: <a href="..."></a> with no text content or aria-label.

Flag: Fake links (href="#"), unlabeled icon buttons, empty links, new-tab links without indication.

2c. Forms

Search for <form>, <input>, <select>, <textarea>:

  • Every input must have an associated <label> (via for/htmlFor attribute matching id, or wrapping the input). placeholder is NOT a substitute for a label.
  • Required fields should have aria-required="true" or the required attribute.
  • Error messages should be associated with their input via aria-describedby.
  • Form groups (e.g., radio buttons) should use <fieldset> + <legend>.
  • Submit buttons should have clear text (not just "Submit" -- what are you submitting?).

Flag: Inputs without labels, placeholder-only inputs, unassociated error messages.

Step 3: Images and Media

3a. Images

  • Every <img> must have an alt attribute.
  • Decorative images should have alt="" (empty alt, not missing alt).
  • Informative images should have descriptive alt text, not filenames (alt="IMG_2847.jpg") or generic text (alt="image", alt="photo", alt="icon").
  • CSS background images that convey information need an alternative (text or aria-label on the container).
  • SVG icons used inline: should have aria-hidden="true" if decorative, or role="img" + aria-label if meaningful.

Flag: Missing alt, filename alt text, generic alt text, meaningful SVGs without labels.

3b. Media

If the project has <video> or <audio> elements:

  • Videos should have captions or a transcript
  • Audio should have a transcript
  • Media players should be keyboard-operable

Flag: Video without captions/transcript, audio without transcript.

Step 4: Color and Visual

4a. Color contrast

This is hard to check from source alone, but look for:

  • Inline styles or CSS with text color + background color combinations that can be evaluated. Common failures:
    • Light gray text on white (#999 on #fff = 2.8:1, needs 4.5:1)
    • White text on bright colors (yellow, light green, light blue backgrounds)
  • Tailwind classes: check for low-contrast combinations (e.g., text-gray-400 bg-white, text-white bg-yellow-300)
  • CSS custom properties: if the project defines color tokens/variables, check them against WCAG AA minimums:
    • Normal text: 4.5:1 ratio minimum
    • Large text (18px+ bold or 24px+): 3:1 ratio minimum
    • UI components and graphical objects: 3:1 ratio minimum

Flag: Detectable low-contrast combinations. Note that full contrast audit requires --live mode.

4b. Color as sole indicator

  • Links distinguished from body text only by color (no underline, no other visual indicator). Links within body text must have a non-color indicator.
  • Form errors indicated only by turning the border red. Must also have text or icon.
  • Status indicators (success/error/warning) using only color. Must also have text or icon.

Flag: Color-only link differentiation in body text, color-only error states.

4c. Motion and animation

  • Check for CSS animations or transitions without prefers-reduced-motion media query support.
  • Flag any animation property used without a corresponding @media (prefers-reduced-motion: reduce) rule somewhere in the project's CSS.
  • Autoplay video or animated content without pause controls.

Flag: Animations without reduced-motion support, autoplay without controls.

Step 5: ARIA Usage

5a. ARIA done right

  • aria-hidden="true" on elements that contain focusable children (traps keyboard users in invisible elements).
  • role attribute with an invalid value.
  • aria-labelledby or aria-describedby pointing to an id that doesn't exist in the same page.
  • Redundant ARIA: role="button" on a <button>, role="link" on an <a>, role="navigation" on a <nav>. These are already implicit.
  • aria-label on elements that don't support it (e.g., <div> without a role, <span>).

Flag: Broken ARIA references, ARIA on focusable hidden elements, redundant roles.

5b. Dynamic content

  • Modals/dialogs: should have role="dialog", aria-modal="true", focus trap, and return focus on close.
  • Toast/notification components: should use role="alert" or aria-live="polite".
  • Loading states: should use aria-busy="true" on the container, or a live region announcing the state change.
  • Content that updates without page reload: should use aria-live regions.

Flag: Modals without dialog role/focus management, dynamic content without live regions.

Step 6: Document-Level

  • <html> has lang attribute (e.g., lang="en")
  • Page <title> is unique and descriptive per page (not just the site name everywhere)
  • Skip-to-content link exists (a visually hidden link at the top of the page that jumps to <main>)
  • Viewport meta doesn't disable zoom: user-scalable=no or maximum-scale=1 are violations

Flag: Missing lang, missing/duplicate titles, missing skip link, zoom disabled.

Live Check (--live flag)

When --live is passed, use WebFetch to check each page's rendered HTML for:

  1. Rendered heading hierarchy -- does the final HTML have correct h1-h6 order?
  2. Rendered landmarks -- are <main>, <nav>, <header>, <footer> present in output?
  3. Rendered form labels -- do inputs have associated labels in the final DOM?
  4. Contrast estimation -- parse inline styles and class-based colors in the rendered output
  5. ARIA reference integrity -- do all aria-labelledby/aria-describedby IDs resolve?

Compare live results against source findings. Flag discrepancies (SSR issues, hydration bugs that break accessibility).

Scoring

Max score: 100 points. Weighted by impact:

CategoryWeightRationale
Keyboard accessibility (2a)20Complete blocker for keyboard/switch users
Forms (2c)15Blocks task completion
Images and alt text (3a)15Core screen reader experience
Heading hierarchy (1b)10Navigation and comprehension
Landmarks (1a)10Screen reader navigation
Buttons and links (2b)10Core interaction
Document-level (Step 6)8Foundation
ARIA usage (5a, 5b)5Correctness
Color/contrast (4a, 4b)5Partial check from source (full check needs --live)
Motion (4c)2Important but narrower impact

Formula: score = (earned_points / applicable_points) * 100

Skip checks that don't apply (no forms = skip form checks, no images = skip image checks).

Grade scale:

ScoreGradeMeaning
90-100ASolid. Minor polish only.
80-89BGood foundation, some gaps.
70-79CUsable but excluding people. Fix the keyboard and form issues.
60-69DSignificant barriers. Needs dedicated work.
0-59FMajor accessibility failures. Prioritize before shipping.

Output Format

## Accessibility Audit -- [project name]
**Score:** [score]/100 ([grade])
**Stack:** [detected stack]
**WCAG Level:** AA (target)

### CRITICAL (blocks entire user groups)
1. **[Category]** [file:line] -- [what's wrong] -- [how to fix]

### SERIOUS (degrades experience significantly)
1. **[Category]** [file:line] -- [what's wrong] -- [how to fix]

### MODERATE (should fix)
1. **[Category]** [file:line] -- [what's wrong] -- [how to fix]

### MINOR (polish)
1. **[Category]** [file:line] -- [what's wrong] -- [how to fix]

### Summary
- [X] critical, [Y] serious, [Z] moderate, [W] minor issues
- Top priority: [the one thing to fix first]

Fix Mode (--fix flag)

Safe to auto-fix:

  • Add lang="en" to <html> if missing
  • Add alt="" to images that are clearly decorative (inside links with text, CSS background replacements). Add alt="TODO: describe this image" to content images missing alt.
  • Add aria-hidden="true" to decorative SVG icons
  • Remove role="button" from <button> elements (redundant)
  • Remove role="link" from <a> elements (redundant)
  • Add rel="noopener" to target="_blank" links if missing

Requires confirmation:

  • Adding aria-label to icon buttons (needs the right label text)
  • Adding skip-to-content link (needs to match page structure)
  • Wrapping inputs with <label> (needs to not break layout)
  • Adding prefers-reduced-motion CSS (needs to know which animations to disable)

Never auto-fix:

  • Color contrast (requires design decisions)
  • Focus management in modals (requires understanding the component logic)
  • Heading hierarchy (restructuring headings can break design intent)
  • ARIA live regions (requires understanding what content updates dynamically)

Rules

  • React Native / Expo projects: Skip this audit. Native accessibility uses accessibilityLabel, accessibilityRole, accessibilityState, etc. -- a completely different model. Note this and stop.
  • Don't flag framework internals. Next.js <Head>, Astro <Layout>, Jinja {% block %} are structural. Check what they render, not the templating syntax.
  • Stack-aware fixes. In JSX it's htmlFor, in HTML it's for. In JSX it's tabIndex, in HTML it's tabindex. Get it right.
  • Severity by impact. A missing skip link is moderate. A click handler on a div with no keyboard equivalent is critical -- it's a complete blocker for keyboard users.
  • Don't penalize what doesn't exist. No forms = no form audit. No media = no media audit.
  • Be specific about fixes. "Add alt text" is useless. "Add alt=\"<describe the image content>\" to <img> at src/templates/<file>.html:<line>" is useful.
  • Prefer semantic HTML over ARIA. The fix for a clickable div is almost always "make it a button," not "add role=button and tabindex=0 and onKeyDown."

Skill Run Logging

After completing this skill, append a log entry to ~/.claude/skill-log.md under the Run Log table. New entries at the top (most recent first).

Format: | YYYY-MM-DD | /skill-name | target (details) | one-line result |

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.