Skip to main content
skill Claude Code CX Codex Cursor GitHub Copilot

better-accessibility — Claude Code skill: accessibility and install

Reviews an interface against WCAG 2.2 and fixes issues in the project’s styling system. Use it to check keyboard navigation and screen-reader behavior.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add jakubkrehel/skills --skill better-accessibility -a claude-code
Open on GitHub

What better-accessibility does

The skill checks semantics, focus, accessible names, forms, screen-reader announcements, motion, and zoom. It walks user flows without a mouse, then checks whether a screen reader announces each control’s name, role, and state. Findings are tied to WCAG 2.2 Level A or AA criteria, and fixes go into the project’s styling system.

Its guidance favors native HTML elements, visible keyboard focus, and deliberate focus handling when dialogs open or routes change. It also checks keyboard alternatives to dragging and accessible form labels and errors. If a custom control replaces native behavior, review that interaction carefully: the skill’s guidance favors the platform default.

Contrast measurement and color changes belong to better-colors; typography and iOS input zoom belong to better-typography. The listed minimum is 4.5:1 for regular text and 3:1 for UI component boundaries. The skill leaves colors unchanged unless asked to fix them. The source ends during its section on dynamic announcements, so this description covers only the rules shown there.

What it helps with

  • check whether a flow works without a mouse
  • find controls missing an accessible name or state
  • connect form errors to fields and focus
  • review keyboard support in dialogs and widgets
  • map accessibility failures to WCAG 2.2 criteria

Example prompts for the agent

  • Review this page’s keyboard navigation and focus against WCAG 2.2.
  • Check the forms for labels, error messages, and screen-reader announcements.
  • Find controls with missing accessible names and fix them in the project’s styling system.

How to install better-accessibility

1Skills CLI (Vercel)

npx skills add jakubkrehel/skills --skill better-accessibility -a claude-code

2Manually: put the files in place

~/.claude/skills/better-accessibility/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/better-accessibility/

From the same set13

The whole set →
better-ui jakubkrehel This skill sets concrete rules for surface details, icons, shadows, and motion. Use it to polish an interface after its underlying interactions work. Claude Code CX Codex Cursor +1 38,900installs better-typography jakubkrehel Reviews interface typography and applies fixes through the project’s styling system. Use it to check text hierarchy, wrapping, truncation and punctuation. Claude Code CX Codex Cursor +1 33,800installs better-colors jakubkrehel Audits color systems, generates ramps, and maps semantic tokens to roles. Use it when hardcoded hex values pile up or text contrast needs verifiable measurement. Claude Code CX Codex Cursor +1 32,200installs better-layout jakubkrehel A skill that sets grouping, alignment, reading order and responsive structure, then stress-tests the result by resizing, translating and mirroring it for RTL. Claude Code CX Codex Cursor +1 30,400installs better-interface jakubkrehel Runs a cross-discipline interface review covering accessibility, layout, copy, typography, color, and UI polish into one ranked report. Claude Code CX Codex Cursor +1 29,700installs better-writing jakubkrehel Writes and reviews UI copy, from button labels to errors and empty states. It keeps product vocabulary consistent and guides users to the next step. Claude Code CX Codex Cursor +1 28,700installs interface-review jakubkrehel Audits pull requests, branches, and uncommitted edits for layout, UI, accessibility, and typography regressions. Keeps focus on what changed rather than pre-existing debt. Claude Code CX Codex Cursor +1 18,100installs variant jakubkrehel This skill builds distinct versions of one UI component and puts them on the page where it will live. Use it to compare design directions before choosing one. Claude Code CX Codex Cursor +1 14,300installs

Similar

vue Anthony Fu This skill guides agents through Vue 3 Composition API, script setup, and reactivity. Use it when writing Vue SFCs or built-in component flows. Claude Code CX Codex Cursor +1 35,800installs game-engine official github Guides GitHub Copilot when building browser games and game engines with HTML5 and JavaScript. Use it for 2D or 3D rendering, physics, collisions, and controls. GitHub Copilot 13,140installs flags react This skill runs React's feature-flag command and explains the results. Use it to compare release channels when a feature behaves differently between them. Claude Code CX Codex Cursor +1 1,100installs frontend-design official anthropics This skill guides intentional visual design for new interfaces and redesigns. Use it when a generic generated UI is not enough. Claude Code Claude.ai 1,025,790installs design-taste-frontend Leonxlnx This skill directs the design of public pages and work screens, then checks the result in a browser through screenshots. Use it when an interface feels generic or unfinished. Claude Code CX Codex Cursor +1 673,100installs prototype Matt Pocock Creates throwaway prototypes for checking state logic or exploring UI before committing the decision to the main codebase. Claude Code 986,201installs hyperframes heygen-com Instructs coding agents on creating, validating, and rendering HTML-based videos using the HyperFrames framework and CLI. Claude Code CX Codex Cursor +1 1,200,000installs hyperframes-cli heygen-com Controls HyperFrames video workflows from the CLI: audits layouts and contrast, edits timeline clips, captures snapshots, and renders locally or in cloud runtimes. Claude Code CX Codex Cursor +1 1,200,000installs

Questions about better-accessibility

How do I install better-accessibility in Claude Code?

Run npx skills add jakubkrehel/skills --skill better-accessibility -a claude-code. The skill is installed at ~/.claude/skills/better-accessibility/SKILL.md.

What does better-accessibility do?

It reviews keyboard behavior, focus, forms, and screen-reader announcements. It maps WCAG 2.2 Level A or AA failures to fixes in the project’s styling system.

How does the skill check keyboard accessibility?

It walks user flows without a mouse and checks that interactions have keyboard paths. For composite widgets, it follows arrow-key navigation; overlays should close with Escape and return focus to their trigger.

Source text

SKILL.md · MIT
---
name: better-accessibility
description: Reviews and fixes keyboard and focus behavior, ARIA, accessible names, forms, screen-reader announcements, motion and zoom against WCAG 2.2.
---

# Accessibility

This skill reviews and fixes semantics, keyboard and focus behavior, accessible names, forms, announcements, motion and zoom. It reports each failure against the WCAG criterion it breaks and writes the fix in the project's styling system.

Reviewing means two walks. Keyboard-only, where every flow completes without a mouse. Then screen-reader, where every control announces a name, a role and its state. When unsure, take the platform default over a custom rebuild, and remove ARIA rather than add it.

Contrast measurement and color fixes belong to `better-colors`. Text sizing, iOS input zoom and language metadata belong to `better-typography`. Spacing between targets and spatial RTL belong to `better-layout`. Label, error and alt-text wording belong to `better-writing`. Animation recipes, hover styling and scroll containment belong to `better-ui`.

## Criteria, not conventions

A finding cites a WCAG 2.2 Level A or AA criterion by number, or a concrete task an assistive-technology user cannot complete. Everything else is a recommendation and never `HIGH`. That covers AAA criteria, APG conventions, the one-`<h1>` and no-skipped-levels outline and the 44px and 40px targets. The criterion thresholds below are exact. The larger targets are heuristics, so keep an established, usable density.

## Native elements first

The first rule of ARIA: don't use ARIA when a native element exists. `<button>` for actions, `<a href>` for navigation, never `<div onClick>`. A real link must support Cmd/Ctrl/middle-click. See [semantics-and-aria.md](semantics-and-aria.md) for landmarks and button-vs-link.

## Disabled means unavailable

Use native `disabled` when a control is genuinely unavailable. Reach for `aria-disabled="true"` only when it should stay focusable, then block pointer, keyboard and form behavior in code and style the state explicitly. The rules are in [semantics-and-aria.md](semantics-and-aria.md).

## Visible focus rings

Style `:focus-visible`, not bare `:focus`. Keyboard users get a ring and mouse users usually don't. Prefer the browser's unmodified indicator.

A custom ring needs a project focus token or another explicit color. It must reach 3:1 against every adjacent color it crosses, `currentColor` included, under 1.4.11. A `2px` solid perimeter with a 3:1 change of contrast is the 2.4.13 AAA target. Never use `outline: none` without a verified replacement, and preserve system colors in forced-colors mode.

A focused element must never sit fully hidden behind a sticky header, footer or banner (2.4.11). Pad the scroller by the sticky chrome's height, a fix `better-layout` owns. Recipes are in [focus-and-keyboard.md](focus-and-keyboard.md).

## Full keyboard support

Every pointer interaction needs a keyboard path. Follow the ARIA APG patterns: Escape closes overlays, arrow keys move within composite widgets, Tab moves between widgets, Enter and Space activate buttons.

Use only `tabindex="0"` to join the natural tab order and `tabindex="-1"` for programmatic focus. Positive values break that order. Composite widgets use roving tabindex, where the active item is `0` and every other is `-1`. Where focus must stay in an input, as in a combobox, use `aria-activedescendant` instead. Key maps per widget are in [focus-and-keyboard.md](focus-and-keyboard.md).

## Trap and restore focus

Prefer `<dialog>` opened with `showModal()`, which makes the background inert and handles Escape. A custom overlay sets `inert` on the background, `role="dialog"` and `aria-modal="true"` on itself. Either way, move focus inside on open and return it to the trigger on close.

Client-side route changes reset nothing. Update `document.title` and move focus to the new view's `<h1>` or `<main>`. Both recipes are in [focus-and-keyboard.md](focus-and-keyboard.md).

## Minimum hit area

WCAG 2.5.8's Level AA baseline is a 24×24 CSS-pixel target, or one of its exceptions. Aim for 44×44px on touch and 40×40px on desktop where density permits. Extend with a pseudo-element when the visible element should stay smaller.

Never let extended hit areas overlap. Give decorative layers `pointer-events: none`, so a glow never swallows the clicks meant for the control beneath it.

Every drag interaction needs a single-pointer alternative, such as buttons or a menu that reorder or move the same item (2.5.7). Sizes, exceptions and collision rules are in [hit-areas.md](hit-areas.md).

## Label and type every control

Every input gets a `<label for>` or a wrapping `<label>`. A placeholder is never a label. Label and control share one hit target, with no dead zone between a checkbox and its text.

Add a valid `autocomplete` token and a descriptive `name` attribute, plus the `type` and `inputmode` that summon the right keyboard. Never block paste; users paste passwords and one-time codes. See [forms.md](forms.md).

## Errors that announce

Validate on submit, never by disabling submit until the form is valid. Mark failing fields `aria-invalid="true"`, point `aria-describedby` at the inline error text and focus the first invalid field. Submit behavior while the request runs is in [forms.md](forms.md).

## Accessible names everywhere

Icon-only buttons need a descriptive `aria-label`. Visible label text must appear in the accessible name. Decorative elements get `aria-hidden="true"`, never on a focusable element.

## Pair color with a second cue

Status needs a redundant cue: an icon, text or an underline alongside the color (1.4.1).

This skill decides which contrast requirement applies:

| Criterion | Applies to | Minimum |
| --- | --- | --- |
| 1.4.3 AA | Text | 4.5:1 |
| 1.4.3 AA | Large text, at least `24px` or `18.67px` bold | 3:1 |
| 1.4.11 AA | UI component boundaries, states and meaningful graphics | 3:1 |

Inactive controls and logos are exempt. Use `better-colors` to measure the rendered pair. When it fails, report the pair and the criterion it misses, and leave the colors alone unless asked.

## Honor prefers-reduced-motion

Wrap motion in `@media (prefers-reduced-motion: no-preference)` so it is opt-in. Under reduced motion, replace slides and scales with opacity cross-fades, and kill parallax and autoplay entirely. See [motion-and-zoom.md](motion-and-zoom.md).

## Nothing the user needs runs on a timer

Anything moving, blinking or updating on its own for more than 5 seconds needs a visible pause control (2.2.2). Toasts carrying an action or an error stay until dismissed. The rules are in [motion-and-zoom.md](motion-and-zoom.md).

## Announce dynamic content

Three mechanisms, three jobs. `aria-describedby` carries field-specific validation. A polite live region (`role="status"`) carries non-urgent updates not tied to a control, such as toasts and result counts. `role="alert"` carries urgent untied errors and nothing else.

Repeated polite announcements need a stable empty region rendered before its text updates. Dynamically inserted alerts vary in support, so test them on the screen readers you target. See [screen-readers.md](screen-readers.md).

## Alt text by purpose

Decorative images get `alt=""`. Informative images describe the meaning. Functional images describe the action, never the picture. The full table is in [screen-readers.md](screen-readers.md).

## Structure is navigation

Use headings that describe their sections and form a coherent outline. Expose one visible primary `<main>` landmark. When repeated navigation or chrome precedes it, make a "Skip to content" link the first focusable element. Anchored headings get `scroll-margin-block-start`.

## Survive zoom and text resize

Text must survive 200% resize (1.4.4), and the page must reflow at 320px width without horizontal scrolling (1.4.10). Text containers take `min-height`, not `height`, and `better-layout` owns the rest of that fix. Never set `maximum-scale=1` or `user-scalable=no` in the viewport meta. iOS input zoom is fixed with `better-typography`'s `16px` rule instead.

## Before you finish

| Pattern | Fix |
| --- | --- |
| `outline: none` or `outline-none` with no `focus-visible` replacement nearby | Restore the browser ring or add a verified custom one |
| `<div onClick` or `<span onClick` | Use `<button>`, or `<a href>` when it navigates |
| `role="button"` or `role="tab"` with no `onKeyDown` | Use the native element, or implement the APG key map |
| `tabIndex={1}` or any positive `tabindex` | Fix the DOM order and use `0` |
| `disabled={!isValid}` on a submit button | Keep it enabled and validate on submit |
| `{msg && <div role="status">`, region mounted with its text | Render the empty region first and update its text |
| `aria-live="assertive"` on a success toast | `role="status"` |
| `<img` with no `alt` attribute | `alt=""` if decorative, otherwise describe the purpose |
| `aria-label` whose text omits the visible label | Start the name with the visible text |
| `aria-hidden` on an ancestor of a button, link or input | Remove it, or make the subtree inert |
| `maximum-scale=1` or `user-scalable=no` | Remove it |
| Tooltip on a natively `disabled` control | Text beside it, or `aria-disabled` so it stays focusable |
| `onDragStart` or a drag library with no button alternative | Add a single-pointer path to the same result |

## Reporting

**Severity.** `HIGH` prevents a task, hides content from assistive technology or creates a systemic failure. `MEDIUM` makes an interaction meaningfully harder. `LOW` is isolated polish. This domain's share of `better-interface`'s escalation triggers is `HIGH` on sight. That is a missing accessible name, a missing focus indicator and a pointer path with no keyboard path. It is also motion ignoring reduced motion, loss at 320px or 200% and meaning carried by color alone.

**Verification.** Without a browser: accessible names on every interactive element, keyboard handlers on non-native controls, focus styles, `prefers-reduced-motion` guards and form labels bound to their inputs. With one: tab the flow in order, read computed names and roles from the accessibility tree, confirm a visible focus indicator at every stop and run an automated audit. Report every check you could not run as `Not verified`.

**Format.** Group findings under the principle each violates, ordered by severity, one row per root cause listing every location it appears in:

| Severity | Location | Before | After | Why |
| --- | --- | --- | --- | --- |

`Location` is `path/to/file:line`. `Why` names the WCAG criterion or principle and the user impact.

End with `Block` when any `HIGH` remains, `Approve` otherwise, leaving the rest in the table as work to do. Never `Approve` coverage you did not inspect. With nothing to report, state "No actionable accessibility findings" and report verification.

© jakubkrehel · MIT · jakubkrehel/skills

See also

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor