Skip to content
Back to skills

Accessibility Auditor

ASecurity

Use when reviewing UI for accessibility — WCAG 2.2 AA, keyboard nav, focus, ARIA, contrast, screen-reader semantics — even on 'is this a11y-OK?' or 'mach das barrierefrei'.

  • 10 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added June 5, 2026
ai-agentsgofrontend

Security analysis

A100/100

Scanned September 12, 2026

npx -y skills add event4u-app/agent-config --skill accessibility-auditor --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Accessibility Auditor?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Accessibility Auditor
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/event4u-app-accessibility-auditor/badge)](https://www.skillsdirectory.com/skills/event4u-app-accessibility-auditor)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
model_tier: medium
name: accessibility-auditor
description: "Use when reviewing UI for accessibility — WCAG 2.2 AA, keyboard nav, focus, ARIA, contrast, screen-reader semantics — even on 'is this a11y-OK?' or 'mach das barrierefrei'."
personas:
  - frontend-engineer
domain: quality
enforced_by:
  - "test:tests/contracts/accessibility_wcag_version_claim.test.ts"
workspaces:
  - engineering
packs:
  - engineering-base
token_budget_class: rich
---

# accessibility-auditor

> Audit a UI surface against WCAG 2.2 AA, keyboard-only operation,
> and screen-reader semantics. Output is a verdict with cited
> failures, not a vibes check. Pair with
> [`tailwind-engineer`](../tailwind-engineer/SKILL.md) for token-level
> contrast fixes and [`ui-component-architect`](../ui-component-architect/SKILL.md)
> for structural fixes (landmarks, heading order).

## When to use

- A new screen, component, or form lands and a11y has not been
  reviewed yet.
- A bug report mentions keyboard, screen reader, focus order,
  contrast, or "user can't reach the X button".
- A modal, dropdown, popover, tab strip, or tree view is being
  introduced — these are the highest-yield bug zones.
- German triggers: "barrierefrei prüfen", "Tastatur-Bedienung",
  "Screenreader testen".

Do NOT use when:

- The visual design itself is the question (palette, type scale) —
  route to [`fe-design`](../fe-design/SKILL.md).
- The diff has no UI surface — accessibility audits without a UI are
  speculation.
- A specific component spec is missing entirely — get the component
  built first via the stack-specific skill, then audit.

## Procedure

### 1. Identify the interaction surfaces

List every interactive element on the screen: links, buttons,
inputs, custom widgets (combobox, tab, dialog, tree). Each row
gets a verdict in step 5; missing one is a coverage failure.

### 2. Walk the four checklists

**Perceivable** — text alternatives for non-text (`alt`, `aria-label`),
contrast ≥ 4.5:1 for body / 3:1 for large or UI components, no
colour-only state ("error in red" must also be iconic or text).
Grounded reference for palette + chart verdicts: the adopted corpus's
WCAG-adjusted token sets (`--domain color`), chart a11y grades +
colorblind fallbacks (`--domain chart`), and mobile touch/a11y rules
(`--domain web`, 44pt targets) via
[`design-intelligence`](../design-intelligence/SKILL.md) — cite the
corpus row; the WCAG 2.2 AA *method* stays this skill's own checklists.
Widget-pattern selection (dialog, combobox, tabs, toast, table, form
errors, drag-reorder …) grounds in the ARIA-APG corpus:
`./scripts-run <skills-root>/corpus-grounding/scripts/ground search
--manifest <skills-root>/accessibility-auditor/data/manifest.json
"<component>"` →
pattern, implementation, WCAG refs, anti-patterns
([`data/aria-patterns.csv`](data/aria-patterns.csv)).

**Operable** — every interactive element reachable by `Tab`, focus
order matches visual order, focus indicator visible (≥ 3:1 against
adjacent), `Esc` closes overlays, no keyboard traps.

**Understandable** — labels associated (`label[for]` or wrapping),
errors named in text (not just border colour), language attribute
on `<html>`, predictable navigation across pages.

**Robust** — landmarks present (`<header>`, `<nav>`, `<main>`,
`<footer>`), heading order without skips, ARIA only when no native
element exists, custom widgets follow ARIA-APG patterns.

**Reduced motion — audit the PRESENTATION, not the presence of the
query.** A `prefers-reduced-motion` block is easy to grep and proves
nothing: `animation: none` on a scroll-revealed section leaves the
content invisible, and a scrubbed sequence with its motion removed
leaves the story untold. So the finding is about what the surface
shows **instead**:

| Motion carries | Reduced-motion presentation | Failure |
|---|---|---|
| A reveal (content fades/slides in) | The content at its **final** state, visible from the start | `opacity: 0` left standing — the content never appears |
| A scrubbed sequence (scroll drives progress) | Each beat at its **resting** state, reachable by ordinary scrolling | Motion disabled and the beats collapse onto each other |
| A transition between states | An instant state change, still announced | The state changes with no perceivable feedback |
| Decoration (parallax, drift, ambient) | Nothing — removal is the correct presentation | — |

Decoration is the only case where removal is the answer, which is why
`animation: none` reads as correct so often and is wrong so often. Ask
per block: *if the motion never plays, is the content still there and
still understandable?* Record the answer, not the query.

**WCAG 2.2 additions — the six criteria 2.1 did not have.** An AA claim is
cumulative: AA conformance means every level-**A** criterion *and* every
level-AA one, so the two level-A rows below sit inside the claim, not beneath
it. Each is audited on its own; a surface that skips one is not AA under 2.2.

| SC | Level | Testable condition | Failure |
|---|---|---|---|
| 2.4.11 Focus Not Obscured (Min.) | AA | `Tab` through every focusable element with sticky headers / footers / cookie bars present — the focused element stays at least partially visible, never fully covered | A sticky bar hides the focused row; the keyboard user cannot see where they are |
| 2.5.7 Dragging Movements | AA | Every drag interaction (reorder, slider, map pan, kanban) has a single-pointer alternative that is not a drag — buttons, a menu, or arrow keys | Reorder is drag-only, so a user who cannot drag cannot reorder |
| 2.5.8 Target Size (Min.) | AA | Every pointer target is ≥ 24×24 CSS px, **or** carries ≥ 24 px spacing to its neighbours, **or** is one of the stated exceptions (inline text, user-agent-controlled, essential) | 16 px icon buttons packed edge-to-edge in a toolbar |
| 3.3.8 Accessible Authentication (Min.) | AA | No login step requires a cognitive function test (remembering, transcribing, puzzle-solving) without an alternative — a password manager can paste, and paste is not blocked | An OTP field that blocks paste, or "type the 3rd character of your memorable word" |
| 3.2.6 Consistent Help | A | Where a help mechanism (contact link, chat, self-help) repeats across pages, it appears in the same relative order on each | Support link in the header on one page, buried in the footer on the next |
| 3.3.7 Redundant Entry | A | Information already entered in the same process is auto-populated or selectable, unless re-entry is essential (confirming a password is essential) | A 4-step checkout asking for the same address twice |

Outside an AA claim, and stated here rather than left silent: **2.4.12 Focus Not
Obscured (Enhanced)** and **2.4.13 Focus Appearance** are level **AAA**. Audit
them on request; their absence is not an AA failure.

### 3. Run the keyboard pass

`Tab` from page start: every interactive element receives focus,
in visual order, with a visible indicator. `Shift-Tab` reverses
cleanly. `Enter` / `Space` activate per role. Arrow keys work in
composite widgets (tab strip, listbox, menu). `Esc` dismisses the
top-most overlay only.

### 4. Run the screen-reader pass

Use VoiceOver (macOS), NVDA (Windows), or `aria-live` log
inspection. Each surface announces: role, name, state, value,
description (in that order). State changes (loading, expanded,
selected, error) announce. Decorative images are silent.

### 5. Score and report

For each surface from step 1:

| Surface | WCAG SC | Pass / Fail | Evidence |
|---|---|---|---|
| Submit button | 1.4.3 | Fail | contrast 3.1:1, expected 4.5:1 |
| Modal | 2.1.2 | Fail | Tab leaves modal — focus trap missing |

Verdict at the bottom: **AA-pass** (zero fails), **AA-pass-with-risk**
(non-blocking gaps + plan), or **AA-fail** (blocking — fix before
ship).

## Output format

```
Scope:        <screen / component / route>
Surfaces:     <count from step 1>
Tools used:   <axe-core | manual | VoiceOver | NVDA — pick at least 2>

Findings:
  1. <SC>  <Pass/Fail>  <Evidence + file:line if known>
  2. ...

Verdict:      <AA-pass | AA-pass-with-risk | AA-fail>
Top 3 fixes:  <ordered by user impact>
```

## Same-ramp contrast + dark-mode self-test (procedures, not a palette)

Two deterministic procedures — they reference the consumer's tokens / an
upstream color ramp, they never vendor a hex table:

- **Same-ramp contrast.** Text on a colored fill uses a **darker stop of the
  same color family**, never plain black/gray dropped on top — same-ramp keeps
  the contrast on-brand and predictable. Title and subtitle are **two different
  stops** of that ramp (hierarchy from the ramp, not from an off-ramp gray).
- **Mandatory dark-mode self-test.** Before finalizing, ask: *"if the background
  were near-black, would every text element still meet 4.5:1 (body) / 3:1
  (large/UI)?"* A ramp that only works on light is a fail. Run the test even
  when the brief is light-only — dark mode arrives later.

The ramp itself is authoritative in [`design-tokens`](../design-tokens/SKILL.md)
(token derivation) and the consumer's [`brand-consistency`](../../rules/brand-consistency.md)
tokens — this procedure sits beside that authority, it does not duplicate the
values.

## Gotcha

- `aria-label` on a `<button>` overrides its text content for
  screen readers — only use when the visible text is not
  descriptive (icon-only buttons).
- `tabindex="-1"` removes from tab order *and* allows programmatic
  focus; `tabindex="0"` adds to tab order. `tabindex >= 1` is
  almost always wrong — fix the source order.
- Native `<button>` and `<a>` come with role + keyboard for free;
  reaching for `role="button"` on a `<div>` is a regression.
- Contrast on disabled state has no WCAG threshold — but if the
  user cannot tell it is disabled, that is a 1.4.1 failure on
  state cue.

## Do NOT

- Do NOT declare AA-pass without a keyboard-only pass; an axe-core
  green is necessary, not sufficient.
- Do NOT add ARIA "to be safe" — wrong ARIA is worse than no ARIA.
  Native semantics first.
- Do NOT silence the audit on "internal-only tool" or "small user
  base"; legal exposure does not scale with audience size in most
  jurisdictions.
- Do NOT close a finding by adjusting the test instead of the UI;
  the user's experience is the ground truth, not the test report.

## Why this skill is rich

WCAG 2.2 AA compliance is non-negotiable detail — each success criterion
has a specific testable condition, failure mode, and remediation path.
The skill carries the WCAG 2.2 additions with concrete test
procedures per criterion (not just "check contrast"), keyboard-navigation patterns
(roving tabindex, trap management, escape-key handling), ARIA role/
property/state tables, and screen-reader-specific edge cases per
assistive technology. Condensing to "check contrast and add aria-labels"
loses the test procedures that turn a vague finding into a reproducible
failure with a specific remedy. Accessibility bugs that are described
vaguely cannot be verified as fixed.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…