npx skills add ...
npx skills add microsoft/a11y-llm-eval --skill building-accessible-ui
npx skills add microsoft/a11y-llm-eval --skill building-accessible-ui
MUST BE USED for any UI work. Invoke this skill before generating, modifying, or reviewing any code that renders, styles, or wires up a user-facing interface — including markup, components, templates, styles, and the JavaScript/TypeScript that drives them. This skill encodes the accessibility (WCAG 2.2 AA) requirements every UI change must satisfy; skipping it produces inaccessible output. Applies across web, mobile, and desktop. If the task touches the UI layer in any way, use this skill first.
Checklist for producing and reviewing accessible UIs. Each rule leads with the platform-agnostic principle and, where relevant, the Web (HTML + ARIA + CSS) implementation. Apply the web guidance only when the output is web.
Detailed rationale lives in references/; widget-specific guidance in components/. Open a file only when it's relevant to the current task. Do not preload. Every file opened and every line a tool prints stays in context — don't re-read.
Ground rules. Use them to resolve conflicts and decide how much custom work is justified. The checklist below is their mechanical application.
A UI inaccessible to realistic users is not "done". Treat accessibility as a first-class criterion alongside correctness, performance, and security — not a finishing step. When scope must be cut, record the gap explicitly. Never claim output is "fully accessible"; state what was addressed and known limitations.
Evaluate designs against these personas; if a decision breaks one, justify it and offer an alternative:
Use the highest option that fits:
<button>, <a href>, <input>, <label>, <fieldset>/<legend>, <dialog>, <details>, <nav>, <main>, headings).aria-describedby, aria-expanded, aria-current, etc.).No ARIA is better than bad ARIA. Don't duplicate native semantics (no role="button" on <button>). Don't use role="menu" for site navigation. Don't invent new patterns when a standard one exists.
Accessibility, performance, security/privacy, and visual design are joint constraints — not dials to trade off. If an optimization removes a label, breaks focus, or hides content from AT, redesign the optimization. Accessible names must not leak secrets, but security is not a reason to ship an unlabeled control — find a labeling approach that doesn't leak data. Visual polish doesn't justify removing focus indicators or semantic structure. Under schedule pressure, prefer cutting scope over shipping an inaccessible feature. When constraints genuinely conflict, surface it explicitly.
Don't rewrite an existing component or shared utility just because it could be more accessible — other code depends on it. When you see issues outside the current task's scope: note them (issue, affected persona, suggested fix) and ask before changing. Fix in place only when the change is required by the task, localized, and low-risk. Inside scope, fix real issues; never silently remove existing affordances (labels, landmarks, focus management, live regions) without an equal-or-better replacement.
Identify which components the request involves (form, checkbox group, radio group, disclosure, modal, full view, etc.) and open the matching components/<name>.md once. Then work the checklist below. Open a references/*.md only when an item is unclear or you need the concrete fix pattern.
Do not claim the output is "fully accessible". State what was addressed and known limitations.
Do NOT use this skill for: backend-only changes, data migrations, build/CI configuration, non-UI tests, or tasks that do not touch the UI layer.
references/structure.md.
<button>, <a>, <input>, <label>, <fieldset>/<legend>, <nav>, <main>, <header>, <footer>, <h1>–<h6>) over <div>/<span> with ARIA. Use ARIA only when no native element fits.<main>; <header>, <nav>, <footer> used when applicable.references/structure.md.
<h1>, typically the first heading in <main>. Set a descriptive <title>.references/keyboard-focus.md.
aria-label is used, include the visible label text. For multiple controls that share a label (e.g., "Remove"), add context ("Remove item: Socks").components/forms.md.
<label for> or wrapping <label>; never placeholder alone. Associate help/error via aria-describedby / aria-errormessage.<fieldset> with a <legend>. Put aria-describedby on the <fieldset> (not on a child <div>, and never on an extra <div role="group"> inside the fieldset — <fieldset> already is the group).required on the control or aria-required="true".tabindex="-1" only for elements that need programmatic (not sequential) focus. → references/keyboard-focus.md.hidden / display: none / aria-hidden="true" used consistently.references/images-graphics.md.
<img> informative → alt; decorative → alt="". Informative <svg> → role="img" + accessible name. Other decorative → aria-hidden="true".references/contrast-forced-colors.md.references/contrast-forced-colors.md.references/reflow.md.references/navigation.md.
<nav>, not role="menu"; aria-expanded on triggers.references/tables-grids.md.references/status-messages.md
aria-live="polite" or aria-live="assertive".references/testing.md before writing any test code for the opt-out signals, strategy precedence, runtime probe order, and reporting rules.
@axe-core/* bindings that match the existing test runner; render the component/page fully so interactive state, focus, and live regions are evaluated.AccessibilityChecks, iOS XCUIAccessibilityAudit, .NET AccessibilityInsights) under the same precedence.references/specs-documentation.md.