Best for
- Use when asked to "improve accessibility", "a11y audit", "WCAG compliance", "screen reader support", "keyboard navigation", or "make accessible".
addyosmani/web-quality-skills/skills/accessibility/SKILL.md
Audit and improve web accessibility following WCAG 2.2 guidelines. Use when asked to "improve accessibility", "a11y audit", "WCAG compliance", "screen reader support", "keyboard navigation", or "make accessible".
Decision brief
Comprehensive accessibility guidelines based on WCAG 2.2 and Lighthouse accessibility audits. Goal: make content usable by everyone, including people with disabilities.
Compatibility matrix
| Platform | Status | Evidence | What to check |
|---|---|---|---|
| Codex | Not declared | No explicit evidence | Portability before use |
| Claude Code | Not declared | No explicit evidence | Portability before use |
| Cursor | Not declared | No explicit evidence | Portability before use |
| Gemini CLI | Not declared | No explicit evidence | Portability before use |
Installation
The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.
npx skills add https://github.com/addyosmani/web-quality-skills --skill "skills/accessibility"Inspect the Agent Skill "accessibility" from https://github.com/addyosmani/web-quality-skills/blob/afa8da942115f2961fdbfa80807ea0b232ff6c00/skills/accessibility/SKILL.md at commit afa8da942115f2961fdbfa80807ea0b232ff6c00. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.
Workflow
When a rendered page is available:
When ARIA is needed, use the correct roles and states. See the ARIA tabs pattern for a complete tablist example.
Review the “WCAG Principles: POUR” section in the pinned source before continuing.
Review the “Conformance levels” section in the pinned source before continuing.
Images require alt text:
Permission review
The documentation includes network, browsing, or remote request actions.
npx lighthouse https://example.com --only-categories=accessibilityThe documentation asks the agent to run terminal commands or scripts.
npx lighthouse https://example.com --only-categories=accessibilityThe documentation asks the agent to run terminal commands or scripts.
npm install @axe-core/cli -gThe documentation includes network, browsing, or remote request actions.
axe https://example.comEvidence record
| Signal | Value | Evidence type | Meaning |
|---|---|---|---|
| Quality score | 96/100 | Computed | Documentation, specificity, maintenance, and trust rules |
| Repository stars | 2,695 | Source | Repository attention, not individual Skill quality |
| Compatibility | 0 platforms | Source | Declared in the catalog source record |
| Usage guide | automated source guide | Editorial | Generated or reviewed according to the visible evidence level |
Pinned source
Comprehensive accessibility guidelines based on WCAG 2.2 and Lighthouse accessibility audits. Goal: make content usable by everyone, including people with disabilities.
When a rendered page is available:
lighthouse_audit. Use mobile navigation mode for a general public page or snapshot mode when reloading would lose authenticated or user-created state.take_snapshot. Exercise the affected flow with the keyboard.If the live tools are unavailable, use Lighthouse CLI or axe for automated coverage and complete the same manual checks. Automated tools detect only a subset of accessibility barriers: a score of 100 is not WCAG conformance, and a low score does not replace issue-level evidence.
| Principle | Description |
|---|---|
| Perceivable | Content can be perceived through different senses |
| Operable | Interface can be operated by all users |
| Understandable | Content and interface are understandable |
| Robust | Content works with assistive technologies |
| Level | Requirement | Target |
|---|---|---|
| A | Minimum accessibility | Must pass |
| AA | Standard compliance | Should pass (legal requirement in many jurisdictions) |
| AAA | Enhanced accessibility | Nice to have |
Images require alt text:
<!-- ❌ Missing alt -->
<img src="chart.png">
<!-- ✅ Descriptive alt -->
<img src="chart.png" alt="Bar chart showing 40% increase in Q3 sales">
<!-- ✅ Decorative image (empty alt) -->
<img src="decorative-border.png" alt="" role="presentation">
<!-- ✅ Complex image with longer description -->
<figure>
<img src="infographic.png" alt="2024 market trends infographic"
aria-describedby="infographic-desc">
<figcaption id="infographic-desc">
<!-- Detailed description -->
</figcaption>
</figure>
Icon buttons need accessible names:
<!-- ❌ No accessible name -->
<button><svg><!-- menu icon --></svg></button>
<!-- ✅ Using aria-label -->
<button aria-label="Open menu">
<svg aria-hidden="true"><!-- menu icon --></svg>
</button>
<!-- ✅ Using visually hidden text -->
<button>
<svg aria-hidden="true"><!-- menu icon --></svg>
<span class="visually-hidden">Open menu</span>
</button>
Visually hidden class:
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
| Text Size | AA minimum | AAA enhanced |
|---|---|---|
| Normal text (< 18px / < 14px bold) | 4.5:1 | 7:1 |
| Large text (≥ 18px / ≥ 14px bold) | 3:1 | 4.5:1 |
| UI components & graphics | 3:1 | 3:1 |
/* ❌ Low contrast (2.5:1) */
.low-contrast {
color: #999;
background: #fff;
}
/* ✅ Sufficient contrast (7:1) */
.high-contrast {
color: #333;
background: #fff;
}
/* ✅ Focus states need contrast too (3:1 against background, WCAG 1.4.11) */
:focus-visible {
outline: 2px solid currentColor;
outline-offset: 2px;
}
Don't rely on color alone:
<!-- ❌ Only color indicates error -->
<input class="error-border">
<style>.error-border { border-color: red; }</style>
<!-- ✅ Color + icon + text -->
<div class="field-error">
<input aria-invalid="true" aria-describedby="email-error">
<span id="email-error" class="error-message">
<svg aria-hidden="true"><!-- error icon --></svg>
Please enter a valid email address
</span>
</div>
<!-- Video with captions -->
<video controls>
<source src="video.mp4" type="video/mp4">
<track kind="captions" src="captions.vtt" srclang="en" label="English" default>
<track kind="descriptions" src="descriptions.vtt" srclang="en" label="Descriptions">
</video>
<!-- Audio with transcript -->
<audio controls>
<source src="podcast.mp3" type="audio/mp3">
</audio>
<details>
<summary>Transcript</summary>
<p>Full transcript text...</p>
</details>
All functionality must be keyboard accessible. Prefer native interactive elements — <button>, <a href>, and form controls handle Enter/Space activation, focus, and assistive-tech semantics for free. Only add manual keyboard handling when you cannot use a native element.
<!-- ❌ Non-interactive element with click only: not focusable, no keyboard activation -->
<div class="card" onclick="handleAction()">Open</div>
<!-- ✅ Best: use a native button -->
<button type="button" onclick="handleAction()">Open</button>
// ✅ When you MUST use a non-interactive element (e.g. div with role="button"),
// make it focusable AND handle keyboard activation. Do NOT add this to a native
// <button> — Enter/Space already fire click, so you'd double-trigger.
element.setAttribute('role', 'button');
element.setAttribute('tabindex', '0');
element.addEventListener('click', handleAction);
element.addEventListener('keydown', (e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
handleAction();
}
});
No keyboard traps. Users must be able to Tab into and out of every component. Use the modal focus trap pattern for dialogs—the native <dialog> element handles this automatically.
/* ❌ Never remove focus outlines */
*:focus { outline: none; }
/* ✅ Use :focus-visible for keyboard-only focus */
:focus {
outline: none;
}
:focus-visible {
outline: 2px solid currentColor; /* inherits text color → already contrast-checked */
outline-offset: 2px;
}
/* ✅ Or pick a brand color and verify ≥3:1 contrast against every background it lands on */
button:focus-visible {
box-shadow: 0 0 0 3px rgba(0, 95, 204, 0.5);
}
When an element receives keyboard focus, it must not be entirely hidden by other author-created content such as sticky headers, footers, or overlapping panels. At Level AAA (2.4.12), no part of the focused element may be hidden.
/* ✅ Account for sticky headers when scrolling to focused elements */
:target {
scroll-margin-top: 80px;
}
/* ✅ Ensure focused items clear fixed/sticky bars */
:focus {
scroll-margin-top: 80px;
scroll-margin-bottom: 60px;
}
Provide a skip link so keyboard users can bypass repetitive navigation. See the skip link pattern for full markup and styles.
Interactive targets must be at least 24 × 24 CSS pixels (AA). Exceptions: inline text links, elements where the browser controls the size, and targets where a 24px circle centered on the bounding box does not overlap another target.
/* ✅ Minimum target size */
button,
[role="button"],
input[type="checkbox"] + label,
input[type="radio"] + label {
min-width: 24px;
min-height: 24px;
}
/* ✅ Comfortable target size (recommended 44×44) */
.touch-target {
min-width: 44px;
min-height: 44px;
display: inline-flex;
align-items: center;
justify-content: center;
}
Any action that requires dragging must have a single-pointer alternative (e.g., buttons, inputs). See the dragging movements pattern for a sortable-list example.
// Allow users to extend time limits
function showSessionWarning() {
const modal = createModal({
title: 'Session Expiring',
content: 'Your session will expire in 2 minutes.',
actions: [
{ label: 'Extend session', action: extendSession },
{ label: 'Log out', action: logout }
],
timeout: 120000
});
}
/* Respect reduced motion preference */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
<!-- ❌ No language specified -->
<html>
<!-- ✅ Language specified -->
<html lang="en">
<!-- ✅ Language changes within page -->
<p>The French word for hello is <span lang="fr">bonjour</span>.</p>
<!-- Navigation should be consistent across pages -->
<nav aria-label="Main">
<ul>
<li><a href="/" aria-current="page">Home</a></li>
<li><a href="/products">Products</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
If a help mechanism (contact info, chat widget, FAQ link, self-help option) is repeated across multiple pages, it must appear in the same relative order each time. Users who rely on consistent placement shouldn't have to hunt for help on every page.
Every input needs a programmatically associated label. See the form labels pattern for explicit, implicit, and instructional examples.
Announce errors to screen readers with role="alert" or aria-live, set aria-invalid="true" on invalid fields, and focus the first error on submit. See the error handling pattern for full markup and JS.
Don't force users to re-enter information they already provided in the same session. Auto-populate from earlier steps, or let users select from previously entered values. Exceptions: security re-confirmation and content that has expired.
<!-- ✅ Auto-fill shipping address from billing -->
<fieldset>
<legend>Shipping address</legend>
<label>
<input type="checkbox" id="same-as-billing" checked>
Same as billing address
</label>
<!-- Fields auto-populated when checked -->
</fieldset>
Login flows must not rely on cognitive function tests (e.g., remembering a password, solving a puzzle) unless at least one of:
<!-- ✅ Allow paste in password fields -->
<input type="password" id="password" autocomplete="current-password">
<!-- ✅ Offer passwordless alternatives -->
<button type="button">Sign in with passkey</button>
<button type="button">Email me a login link</button>
Prefer native elements:
<!-- ❌ ARIA role on div -->
<div role="button" tabindex="0">Click me</div>
<!-- ✅ Native button -->
<button>Click me</button>
<!-- ❌ ARIA checkbox -->
<div role="checkbox" aria-checked="false">Option</div>
<!-- ✅ Native checkbox -->
<label><input type="checkbox"> Option</label>
When ARIA is needed, use the correct roles and states. See the ARIA tabs pattern for a complete tablist example.
Use aria-live regions to announce dynamic content changes without moving focus. See the live regions pattern for markup and a showNotification() helper.
Prefer a live Lighthouse audit that returns failing rendered nodes directly to the agent. With Chrome DevTools MCP, this is lighthouse_audit. Otherwise:
# Lighthouse accessibility audit
npx lighthouse https://example.com --only-categories=accessibility
# axe-core
npm install @axe-core/cli -g
axe https://example.com
prefers-reduced-motion: reduceSee the screen reader commands reference for VoiceOver and NVDA shortcuts.
Frequently asked questions
Comprehensive accessibility guidelines based on WCAG 2.2 and Lighthouse accessibility audits. Goal: make content usable by everyone, including people with disabilities.
The source record exposes this install command: npx skills add https://github.com/addyosmani/web-quality-skills --skill "skills/accessibility". Inspect the command and pinned source before running it.
Static rules flagged network, exec-script in the source; the page lists the matching lines and excerpts.
Alternatives
microsoft/hve-core
Consolidated accessibility skill entrypoint for WCAG 2.2, ARIA Authoring Practices, cognitive accessibility, Section 508, EN 301 549, design intent verification, and the Accessibility Planner workflow.
prowler-cloud/prowler
PostgreSQL indexing best practices for Prowler: index design, partial indexes, partitioned table indexing, EXPLAIN ANALYZE validation, concurrent operations, monitoring, and maintenance. Trigger: When creating or modifying PostgreSQL indexes, analyzing query performance with EXPLAIN, debugging slow queries, reviewing index usage statistics, reindexing, dropping indexes, or working with partitioned table indexes. Also trigger when discussing index strategies, partial indexes, or index maintenance
oaustegard/claude-skills
Generate hierarchical _FEATURES.md files that describe what a codebase DOES from a user/consumer perspective, anchored to source symbols via tree-sitting. Supports large complex codebases through feature-driven decomposition into sub-feature files. Uses a multi-pass synthesis: orientation → detail → overview rewrite. Use when someone says "what does this do", "document features", "feature inventory", "_FEATURES.md", or needs to understand a codebase's purpose before modifying it. Complements tre
HKUDS/Vibe-Trading
Create, modify, and optimize quantitative trading strategies, then backtest and evaluate them.