Skip to content
Beta Multi-model support (OpenAI, Gemini, and more) launching soon.

component-a11y-gate

Installable Ships in design-to-code-builder — or copy the raw skill below.
Open Claude.ai

Paste into Claude Code, Claude.ai, the desktop app, or the browser extension — ⌘/Ctrl+V.

ExperimentalNo security review

Component Accessibility Gate — WCAG 2.2 AA

Static analysis of component source files against WCAG 2.2 AA. This skill catches the structural and semantic issues that automated runtime tools (axe, Lighthouse) cannot evaluate until the component is rendered — so it gates accessibility debt at the point of creation, not after QA.

Usage

/component-a11y-gate <target> [options]

Target: file path, directory, or diff to check only currently staged/changed files.

Options:

Flag Values Default Description
--tokens file path auto-detect Token file for resolving contrast pairs
--adapter react, razor, astro, vue auto-detect Markup dialect
--wcag-level aa, aaa aa Contrast gate threshold

Examples:

/component-a11y-gate src/components/Button/
/component-a11y-gate diff --adapter react --tokens src/tokens/tokens.json
/component-a11y-gate src/components/ --wcag-level aaa

Phase 1 — Gather Files

  1. Resolve the target to a list of files with UI relevance:
    • React/TypeScript: .tsx, .jsx, .ts, .js, .module.css, .css, .scss
    • Razor/.NET: .cshtml, .razor, .html
    • Astro: .astro, .css, .scss
    • Vue: .vue, .css, .scss
  2. If diff mode: run git diff --staged --name-only and filter to UI-relevant extensions.
  3. Read the token file from --tokens or auto-detect at common paths: tokens/tokens.json, src/tokens/tokens.json, tokens/tokens.css

Phase 2 — Contrast Analysis

For every hardcoded color value found in the component source, check against the token layer.

2.1 Flag raw color values (not using tokens)

Patterns to detect:

  • Inline styles: style={{ color: '#333' }}
  • Hardcoded Tailwind arbitrary values: text-[#333], bg-[#0057B8]
  • CSS values outside a custom property reference: color: #333;
  • SCSS variables with raw values not derived from the token file

Severity: serious — raw values bypass the design system's accessibility guarantees.

2.2 Resolve token references and compute contrast

For each CSS custom property pair or token reference where foreground and background are both identifiable, resolve the values from the token file and compute the contrast ratio.

Use the W3C relative luminance formula:

sRGB channel: c_lin = c <= 0.04045 ? c/12.92 : ((c+0.055)/1.055)^2.4
L = 0.2126*R_lin + 0.7152*G_lin + 0.0722*B_lin
contrast = (L_lighter + 0.05) / (L_darker + 0.05)

Report as a table:

| Element | FG token | BG token | Ratio | Gate | Result |
|---------|----------|----------|-------|------|--------|
| .btn__label | --color-on-interactive-primary | --color-interactive-primary | 6.1:1 | 4.5:1 | PASS |

2.3 Focus indicator contrast (SC 1.4.11 + 2.4.11)

Locate :focus, :focus-visible, and outline CSS rules. Check:

  • Focus ring color against adjacent background: must be ≥ 3:1
  • Focus indicator perimeter: minimum 2 CSS pixels of enclosed outline (SC 2.4.11 WCAG 2.2)
  • outline: none or outline: 0 with no replacement = serious violation

Phase 3 — Semantic and ARIA Review

3.1 Identify interactive patterns

Scan for:

  • onClick, @click, v-on:click, @onclick handlers on non-interactive elements (<div>, <span>, <p>) = critical unless role + tabindex="0" + keyboard handler present
  • Custom interactive elements missing role attribute = critical
  • ARIA roles that do not match the HTML element (e.g. role="button" on <a>) — flag for review

3.2 Required ARIA attributes by role

Role Required attributes Missing =
button aria-disabled when disabled moderate
checkbox aria-checked critical
switch aria-checked critical
combobox aria-expanded, aria-controls serious
dialog aria-modal="true", aria-labelledby serious
tab aria-selected, aria-controls serious
tabpanel aria-labelledby moderate
slider aria-valuenow, aria-valuemin, aria-valuemax critical
progressbar aria-valuenow, aria-valuemin, aria-valuemax serious
alertdialog aria-labelledby, aria-describedby serious

3.3 aria-label quality

Flag:

  • aria-label on non-interactive elements without a role = minor
  • aria-label that duplicates the visible text exactly — redundant but not harmful; note it
  • aria-label that is generic ("icon", "button", "close") = serious (SC 2.5.3 Label in Name)
  • aria-labelledby or aria-describedby referencing an ID that does not exist = critical

3.4 Image alt text

  • <img> without alt attribute = critical
  • <img alt=""> on informative image = critical (check role="presentation" or aria-hidden consistency)
  • SVG without aria-hidden="true" (decorative) or <title> + aria-labelledby (informative) = serious
  • CMS-managed images (Sitecore <Image />, Optimizely <img> bound to ImageData): note that alt must come from the content model, not be hardcoded

3.5 Form field labelling (SC 1.3.1, 3.3.1, 3.3.2)

  • <input>, <select>, <textarea> without an associated <label for> or aria-labelledby = critical
  • Required fields with no required or aria-required="true" = moderate
  • Error messages not linked to their field via aria-describedby = serious

Phase 4 — Keyboard Interaction Model

4.1 Tab stop correctness

  • tabindex > 0 anywhere = serious (breaks natural tab order; SC 2.4.3)
  • Interactive element with tabindex="-1" that receives focus programmatically (e.g. modal target, skip link destination) = acceptable — note it

4.2 Keyboard activation (SC 2.1.1)

Composite widget keyboard models expected:

Widget Expected keys
Button / Link Enter (and Space for buttons)
Menu item Enter; arrow keys to navigate; Escape to close
Tab Arrow keys to move between tabs; Tab to move into/out of tabpanel
Tree item Arrow keys; Enter/Space to expand; Home/End
Grid cell Arrow keys; Enter to activate; Escape to cancel
Combobox Type to filter; Arrow keys to navigate listbox; Escape to dismiss

Flag any composite widget that only handles onClick without onKeyDown/onKeyUp = critical.

4.3 Focus management

  • Modal/dialog opened without moving focus inside it = critical (SC 2.1.1)
  • Modal closed without returning focus to trigger = serious
  • Keyboard trap: modal that does NOT trap focus (focus escapes to background) = critical (SC 2.1.2)
  • Dynamic content inserted without focus or live region announcement = moderate

Phase 5 — Target Size (SC 2.5.8 — WCAG 2.2)

Scan for explicit width and height values on interactive elements.

  • Targets smaller than 24×24 CSS pixels with no 24 px spacing offset = moderate
  • Icon-only buttons (aria-label present, no text) with width/height < 24px = moderate
  • Inline links in dense text blocks: note risk; not automatically flaggable from static analysis

Phase 6 — Output Report

## Accessibility Gate — <ComponentName>

**Target:** <file path>
**Standard:** WCAG 2.2 Level AA
**Token file:** <resolved path or "not found">

### Verdict: PASS / FAIL

### Findings

| # | Severity | SC | Category | Description | Fix |
|---|---|---|---|---|---|
| 1 | critical | 1.1.1 | Alt text | `<img src={props.image}>` missing alt attribute | Add `alt={props.imageAlt ?? ''}` |
| 2 | serious | 1.4.3 | Contrast | `#6B6B6B` on `#C4C4C4` = 3.2:1 (need 4.5:1) | Use `--color-on-interactive-disabled` token |

---

### Contrast Table
<table from Phase 2>

---

### WCAG 2.2 New Criteria Status
- SC 2.4.11 Focus Appearance: PASS / FAIL / MANUAL CHECK
- SC 2.5.8 Target Size: PASS / FLAG / MANUAL CHECK
- SC 3.3.7 Redundant Entry: N/A (no multi-step form)
- SC 3.3.8 Accessible Authentication: N/A (no auth flow)

---

### Coverage Note
Static analysis covers: HTML structure, ARIA attributes, CSS focus styles, hardcoded colors.
Static analysis cannot cover: rendered contrast of dynamically set theme values, keyboard
focus order in a running browser, screen reader announcement order.
Complement with /accessibility-wcag-scan on the running application.

Severity gates for merge decisions:

  • Any critical = recommend blocking merge
  • serious = resolve before merge; companion ticket acceptable if acknowledged
  • moderate / minor = advisory backlog items
Technical details
Plugin
design-to-code-builder
Author
Dakota Smith
Skill name
component-a11y-gate
Maturity
experimental
Security review
No security review
Owners
  • engineering
  • design
Argument hint
<file-or-directory> [--tokens <path>] [--adapter react|razor|astro|vue] [--wcag-level aa|aaa]
Allowed tools
  • Read
  • Glob
  • Grep
  • Write
  • Bash(git diff *)
  • Bash(git show *)
  • Bash(node *)
Source
plugins/design-to-code-builder/skills/component-a11y-gate/SKILL.md

Edit this skill on GitHub — opens GitHub's web editor. No git knowledge needed.