agentleFS
robritacca-dotcomrobritacca-dotcom/rift-ds/.claude/skills/accessibility-audit/SKILL.md

accessibility-audit

Skill9 starsChanged 7 days agoMITView on GitHub

Audit a component or page for accessibility violations against WCAG 2.1 AA criteria. Use when asked for an accessibility audit, a11y check, WCAG compliance check, or "is X accessible".

55 other projects use a version of this, 1 of them edited.

Adopted by

Most recently taken up by

Used with

Projects with it also use design-system-audit, flaky-test-triage and 9 more.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • jpoindexterSkill

    design-system-audit

    Audit code for design system violations - grid spacing, tokens, existing components

    Also in 4 projects that use this

  • SUDARSHANCHAUDHARISkill

    flaky-test-triage

    Diagnoses inconsistent test results by separating product nondeterminism, automation defects, shared data, timing, infrastructure, environment, order, and concurrency effects.

    Also in 3 projects that use this

  • tekumaraSkill

    api-design-review

    Reviews REST API design by inventorying routes, finding overlapping functionality, comparing payloads and pagination, and checking resource naming, URL structure, identifiers, errors, idempotency, and timestamps. Use when asked to review API routes, compare endpoints, find redundant or superseding operations, assess contract consistency, or run a REST API design review.

    Also in 3 projects that use this

  • BufferoverflovvSkill

    observability-setup

    Add production observability to a FastMCP server: request IDs, slow-request logging, structured log fields, and optional Prometheus metrics. Use when: hardening logging for production, adding request tracing or correlation IDs, setting up slow-request alerts, adding a /metrics endpoint, or improving structured log output beyond the base middleware.

    Also in 3 projects that use this

  • mmondoraSkill

    infrastructure-as-code

    Infrastructure as Code with Terraform and Pulumi. State management, modularity, drift detection, secrets handling. Use when provisioning cloud resources, writing Terraform/Pulumi modules, or managing infrastructure configuration.

    Also in 3 projects that use this

  • Sagargupta16Skill

    upgrade-dependencies

    Upgrade a project's dependencies one at a time, running the test suite after each bump and reverting the ones that break it. Use it during routine dependency maintenance, when a batch of updates has accumulated; before a major release, to go into it on current and patched dependencies; when Renovate or Dependabot PRs have piled up and you want them resolved locally in one sitting; when a security advisory means you need the patched version in, and you need to know what it breaks.

    Also in 3 projects that use this

The file

We split this skill into the rules it gives an agent

8 rules. 0 are common, 5 are distinctive, and 3 are very specific to this project.

  • 0

    Common

    Most of the 46 edited versions we read keep these.

  • 5

    Distinctive

    This author's own choices. Worth a look.

  • 3

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Use this skill when asked to check accessibility, run an a11y audit, or find WCAG issues — phrases like "accessibility audit", "a11y check …

    line 15
  2. Very specific:

    If that is green, every violation axe can detect is already absent — and re-checking icon-only button names, label association, …

    line 25
  3. Distinctive:

    [manual]: All interactive elements are reachable by Tab, in an order that makes sense — axe cannot judge order

    line 56
  4. Very specific:

    Every interactive element has a :focus-visible rule in its CSS

    line 63
  5. Very specific:

    Visual audit (from screenshots): Start the preview server and screenshot the target in both light and dark mode (follow the visual-review …

    line 71
  6. Distinctive:

    Text sizing: No text visually below ~12px (WCAG 1.4.4)

    line 73
  7. Distinctive:

    Stop the server when done.

    line 77
  8. Distinctive:

    If clean: "No accessibility violations found.

    line 95

“Common” is measured: kept by at least 6 in 10 of the 46 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

accessibility-audit

Audit a component or page for accessibility violations against WCAG 2.1 AA criteria.

When invoked

Use this skill when asked to check accessibility, run an a11y audit, or find WCAG issues — phrases like "accessibility audit", "a11y check on [component/page]", "check WCAG compliance", "is [X] accessible".

What is already automated — read this before auditing anything

Axe runs on every Storybook story and fails the build. .storybook/preview.ts sets a11y.test: 'error', so npm run test (and therefore CI and npm run verify) already enforces WCAG 2.1 AA across the whole library — and the same run executes any story play function, so behavior a story asserts (focus, dismissal, keyboard) is enforced too. Start by running it:

npm run test

If that is green, every violation axe can detect is already absent — and re-checking icon-only button names, label association, role="dialog" naming or ARIA parent/child relationships by hand is duplicated effort.

This skill exists for the three things that gate does not cover:

  1. Colour contrast — excluded from the axe gate entirely. color-contrast is switched off in .storybook/preview.ts by a settled decision of the owner's. Read that override's comment first: it is the authoritative record of why, and the single place the details belong. Since the 2026-08-20 split of the action colour by mode the shipped pairs the rule used to fail all clear AA; the rule stays off because the action colour is a token consumers re-point to their own palettes, so the gate would be judging a value the system does not own. One slice of contrast is build-enforced at token level instead: scripts/validate-theme-presets.mjs holds every action fill against the label or icon components draw on it — resting, hover and pressed, in both themes, for the shipped tokens and every preset — and its ACTION_PAIRINGS table is the authoritative list of what it covers. Every other rendered pair (text and surfaces, status, charts, alpha composites over real content) is the manual auditor's job, and the single highest-value thing to audit: nothing else checks it. Never propose re-enabling the rule without asking the owner first.
  2. What axe cannot see. Axe catches roughly a third of WCAG issues. It cannot tell whether alt text is meaningful, whether focus order makes sense, or whether a helper message should have been associated with its control. (Behavior a story's play function asserts is covered — Dialog.stories.tsx proves the modal focus trap, restore, and stacked Escape in CI — so the manual job is the overlays with no play coverage yet.) (Two such bugs once shipped undetected until a manual survey found them: Dropdown announced neither its helper text nor its error state. Both were since fixed by moving Dropdown onto Field, but it took the manual survey, not axe, to find them.)
  3. Website pages beyond the automated sample. A page-level axe pass (scripts/validate-website-a11y.mjs, in verify and CI) now runs against the served site in both themes with the same rule set — but only over the route sample in scripts/served-site.mjs, at one desktop viewport. Full-site sweeps, mobile viewports, and any page outside that sample remain this skill's job.

Report a finding as already-enforced if npm run test or the page-level axe pass would have caught it; that tells the reader the gate is working rather than implying a gap.

Instructions

  1. Determine scope. Accept one of:
    • A component name (e.g. Dropdown) → audits src/components/Dropdown/Dropdown.tsx and its CSS (the chat widget's own components are the .tsx modules in src/chat/; read the folder rather than a list. Its question flow moves focus deliberately: into the first option when a set of questions holds the composer, and back to the composer once the set is answered or skipped; check both by keyboard)
    • A website page URL (e.g. /components/button) → audits the live rendered page
    • all-components → audits all components in src/components/ and the chat widget in src/chat/
  2. Read the source files. For each component in scope, read the .tsx and .css files before taking screenshots.
  3. Structural audit (from source code). Most items here are already enforced by axe — spend your effort on the ones marked [manual], which it cannot evaluate:

    Semantic HTML & ARIA:

    • Interactive elements use correct roles (button, link, checkbox, etc.) — never a <div onClick> without role and tabIndex
    • Icon-only <button> elements have aria-label describing their action
    • [manual] <img> elements have meaningful alt text — axe only checks that the attribute exists; decorative images use alt=""
    • Form inputs are associated with <label> via htmlFor/id, or have aria-label
    • Modals and dialogs use role="dialog" and aria-modal="true", with aria-labelledby pointing to the title
    • Lists use <ul>/<ol> + <li>, not <div> stacks
    • Heading hierarchy is logical — no h3 before h2, no skipped levels

    Keyboard Navigation:

    • [manual] All interactive elements are reachable by Tab, in an order that makes sense — axe cannot judge order
    • Custom interactive components handle onKeyDown for Enter/Space (buttons) and arrow keys (any component with roving or list focus — radio groups, segmented controls, listboxes, tablists)
    • [manual where no play function covers it] Modal/dialog actually traps focus while open and restores it to the trigger on close — axe sees the attributes, not the behaviour. The modal overlays share one behavior implementation (design.md's Components intro owns the contract), so a real trap/restore defect there is a finding against all of them, not one. The site chat is modal only in some of its forms, and its floating card's move and size grips are pointer-only by a recorded decision: design.md's ChatWidget spec says which forms trap focus and why the grips are not a finding
    • Escape key closes dismissible overlays (any floating panel — tooltips, popovers, menus, dialogs, pickers), and only the topmost: a popover, menu or visible tooltip open inside a dialog closes before the dialog does, and a press on a dialog's backdrop with a menu open closes only the menu. Every overlay dismisses through the shared layer stack (scripts/validate-overlay-listeners.mjs keeps it so), and Dialog.stories.tsx's nested-overlay stories assert the contract; a component handling Escape in its own keydown handler must mark it handled with preventDefault(), so check that on anything new
    • A literal English accessible name the consumer cannot replace is a finding: it cannot be localised. scripts/validate-accessible-names.mjs catches literal aria-label, aria-roledescription and *Label attributes, and scripts/validate-visible-text.mjs literal JSX text; [manual] check English built in string literals and arrays (a weekday list, a ${n} results template), which neither can see

    Focus Styles:

    • Every interactive element has a :focus-visible rule in its CSS
    • Focus ring uses the action colour token (--color-action-primary-bg) — design.md's action-colour rules are the authoritative list of sanctioned uses. Flag any outline: none without a visible replacement

    Motion (axe evaluates none of this):

    • [manual] Anything that animates for more than five seconds, or loops indefinitely, can be paused, stopped, or hidden (WCAG 2.2.2). CSS motion satisfies this through the reduced-motion block in tokens-motion.css, which carries two mechanisms and whose own header comment owns the contract: token collapse for token-consuming CSS, and a universal * guard that also covers hardcoded and ds-allow(motion)-sanctioned literal timings (an infinite loop on an off-scale duration is still guarded). Read it there rather than assuming which half applies
    • [manual] Animation driven from JavaScript is outside that guard — a requestAnimationFrame loop cannot be seen by CSS, so each one has to check prefers-reduced-motion itself. Enumerate the JS-side checks with a grep for prefers-reduced-motion across src/components/**/*.tsx, src/chat/**/*.{ts,tsx} (the streaming reveal's check is in a .ts file) and website/src — the grep is the inventory, not any list written here (the site's ambient background, which renders a single static frame under the preference, is one illustration; more exist and new ones keep arriving) — and confirm each still honours the preference rather than assuming the token layer covers it. That grep has one known blind spot: the recharts-backed charts animate their marks in from JavaScript but never contain the string — their guard is recharts' own isAnimationActive: 'auto' default, and design.md's chart-set spec owns the contract (a literal true would override the guard). Run a second grep for isAnimationActive across src/components/ — the one expected hit is the shared entrance hook in src/components/Chart/useChartAnimation.ts, which keeps recharts' 'auto' guard while an entrance is due and sets false once it has played (design.md's chart-set spec sanctions it); a literal true, or a chart setting the flag without the hook, is a finding to check against that spec
    • [manual] Motion triggered by interaction (parallax, cursor-reactive effects) is disabled under reduced motion, or is not essential (WCAG 2.3.3)
  4. Visual audit (from screenshots). Start the preview server and screenshot the target in both light and dark mode (follow the visual-review skill pattern). Check:

    • Colour contrast (the priority — axe does not check it): compute the ratio for every foreground/background pair actually rendered, not just body text. Flag anything below 4.5:1 for normal text or 3:1 for large text and UI components (WCAG 1.4.3 / 1.4.11). Note which token is used. The color-contrast axe rule is off for every pair (see item 1 under "What is already automated"); the action-fill pairings are the one slice the build gates, so cross-check a failing action pair against ACTION_PAIRINGS in scripts/validate-theme-presets.mjs — a pair it lists is already enforced (a hit there means the render is not using the token the table names, unless the cell is pinned in SANCTIONED_AA_GAPS in the same script, which is an owner-accepted gap to note rather than raise), and a label or icon on an action fill that it does not list is a gap in the table worth reporting.
    • Text sizing: No text visually below ~12px (WCAG 1.4.4)
    • Focus visibility: Confirm focus rings are clearly visible in both light and dark themes
    • Forced colors (WCAG 1.4.11 under high contrast): render the target with forced colors on (Playwright's forcedColors: 'active', or the browser's emulation) and check that every state carried by a fill (checked, selected, on, a count) still stands apart from the page, that a floating panel keeps an edge once its shadow is dropped, and that focus rings still show. src/tokens/tokens-forced-colors.css re-points the state-bearing roles at system colours (design.md's Forced colors section owns which); the page-level check covers only the table bench (FORCED_CHECKS in scripts/validate-website-a11y.mjs), so anything else is this audit's to judge. A state that vanishes is a finding against the token layer, not the component, unless the component draws the state outside the tokens.

    Stop the server when done.

  5. For each issue, report:

    src/components/FilterMenu/FilterMenu.tsx:84 — WCAG 4.1.2 Name, Role, Value [Critical]
    Trigger button has no accessible name. Icon-only button needs aria-label="Open filters".

    (The example is fictional by design — FilterMenu is not a real component; it illustrates the report shape only.)

    Severity:

    • Critical — blocks keyboard or screen reader users entirely
    • Moderate — degrades experience significantly
    • Minor — best practice violation, low direct impact
  6. Summarise:
    • X critical · Y moderate · Z minor
    • If clean: "No accessibility violations found. Component meets WCAG 2.1 AA."

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.