New: Earn 20% as an AgentAlley affiliate. Share your link and earn on every sale you refer. Join now New: Earn 20% as an affiliate. Join now

Audit and improve web accessibility following WCAG 2.2

Accessibility (a11y)

by addyosmani · MIT license · ★ 2,832 on GitHub · updated Aug 24

Accessibility (a11y) cover

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".

---
name: accessibility
description: 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".
license: MIT
metadata:
  author: web-quality-skills
  version: "2.0"
---

# Accessibility (a11y)

Comprehensive accessibility guidelines based on WCAG 2.2 and Lighthouse accessibility audits. Goal: make content usable by everyone, including people with disabilities.

## Evidence-led audit workflow

When a rendered page is available:

1. Run a live Lighthouse Accessibility audit when that capability is available; with Chrome DevTools MCP, use `lighthouse_audit`. Use mobile navigation mode for a general public page or snapshot mode when reloading would lose authenticated or user-created state.

Overview

Comprehensive accessibility guidelines based on WCAG 2.2 and Lighthouse accessibility audits. Goal: make content usable by everyone, including people with disabilities.

Manual install (npx, ZIP)
Claude Codenpx skills add addyosmani/web-quality-skills --skill accessibility -g -a claude-code
Claude Code (manual)mkdir -p ~/.claude/skills && curl -sL https://codeload.github.com/addyosmani/web-quality-skills/tar.gz/afa8da942115 \ | tar -xz -C ~/.claude/skills --strip-components=2 web-quality-skills-afa8da942115/skills/accessibility
Windows (PowerShell)New-Item -ItemType Directory -Force "$HOME\.claude\skills" | Out-Null; Invoke-WebRequest "https://m.agentalley.io/zip/32a9b78c22681080788b/accessibility.zip" -OutFile "$env:TEMP\accessibility.zip"; Expand-Archive "$env:TEMP\accessibility.zip" -DestinationPath "$HOME\.claude\skills" -Force
Claude.ai / desktopDownload the ZIP and upload it under Settings → Capabilities → Skills.
Codex, Cursor, other agentsPoint them at SKILL.md. The other files are plain text.

Connects with Agent Alley MCP · agentalley.io/mcp

Files included

  • SKILL.md14.0 KB
  • references/2 files · 14.8 KB
Read the files here
addyosmani/afa8da93 files
Shared references1SKILL.md reads these from elsewhere in the repo. Not in the ZIP.Get them on GitHub ↗
SKILL.md
Show the full text465 lines

Accessibility (a11y)

Comprehensive accessibility guidelines based on WCAG 2.2 and Lighthouse accessibility audits. Goal: make content usable by everyone, including people with disabilities.

Evidence-led audit workflow

When a rendered page is available:

  1. Run a live Lighthouse Accessibility audit when that capability is available; with Chrome DevTools MCP, use lighthouse_audit. Use mobile navigation mode for a general public page or snapshot mode when reloading would lose authenticated or user-created state.
  2. Use failed audit nodes to localize the relevant component or template instead of searching the whole repository for generic patterns.
  3. Inspect a rendered accessibility-tree snapshot for names, roles, states, landmarks, and heading structure; with Chrome DevTools MCP, use take_snapshot. Exercise the affected flow with the keyboard.
  4. Fix the source, then re-run the same audit and manual interaction.

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.

WCAG Principles: POUR

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

Conformance levels

Level Requirement Target
A Minimum accessibility Must pass
AA Standard compliance Should pass (legal requirement in many jurisdictions)
AAA Enhanced accessibility Nice to have

Perceivable

Text alternatives (1.1)

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;
}
Color contrast (1.4.3, 1.4.6)
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>
Media alternatives (1.2)
<!-- 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>

Operable

Keyboard accessible (2.1)

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.

Focus visible (2.4.7)
/* ❌ 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);
}
Focus not obscured (2.4.11) — new in 2.2

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.

Target size (2.5.8) — new in 2.2

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;
}
Dragging movements (2.5.7) — new in 2.2

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.

Timing (2.2)
// 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
  });
}
Motion (2.3)
/* 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;
  }
}

Understandable

Page language (3.1.1)
<!-- ❌ 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>
Consistent navigation (3.2.3)
<!-- 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>
Consistent help (3.2.6) — new in 2.2

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.

Form labels (3.3.2)

Every input needs a programmatically associated label. See the form labels pattern for explicit, implicit, and instructional examples.

Error handling (3.3.1, 3.3.3)

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.

Redundant entry (3.3.7) — new in 2.2

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>
Accessible authentication (3.3.8) — new in 2.2

Login flows must not rely on cognitive function tests (e.g., remembering a password, solving a puzzle) unless at least one of:

  • A copy-paste or autofill mechanism is available
  • An alternative method exists (e.g., passkey, SSO, email link)
  • The test uses object recognition or personal content (AA only; AAA removes this exception)
<!-- ✅ 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>

Robust

ARIA usage (4.1.2)

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.

Live regions (4.1.3)

Use aria-live regions to announce dynamic content changes without moving focus. See the live regions pattern for markup and a showNotification() helper.


Testing checklist

Automated testing

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
Manual testing
  • Keyboard navigation: Tab through entire page, use Enter/Space to activate
  • Screen reader: Test with VoiceOver (Mac), NVDA (Windows), or TalkBack (Android)
  • Zoom: Content usable at 200% zoom
  • High contrast: Test with Windows High Contrast Mode
  • Reduced motion: Test with prefers-reduced-motion: reduce
  • Focus order: Logical and follows visual order
  • Target size: Interactive elements meet 24×24px minimum

See the screen reader commands reference for VoiceOver and NVDA shortcuts.


Common issues by impact

Critical (fix immediately)
  1. Missing form labels
  2. Missing image alt text
  3. Insufficient color contrast
  4. Keyboard traps
  5. No focus indicators
Serious (fix before launch)
  1. Missing page language
  2. Missing heading structure
  3. Non-descriptive link text
  4. Auto-playing media
  5. Missing skip links
Moderate (fix soon)
  1. Missing ARIA labels on icons
  2. Inconsistent navigation
  3. Missing error identification
  4. Timing without controls
  5. Missing landmark regions

References

1---
2name: accessibility
3description: 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".
4license: MIT
5metadata:
6 author: web-quality-skills
7 version: "2.0"
8---
9 
10# Accessibility (a11y)
11 
12Comprehensive accessibility guidelines based on WCAG 2.2 and Lighthouse accessibility audits. Goal: make content usable by everyone, including people with disabilities.
13 
14## Evidence-led audit workflow
15 
16When a rendered page is available:
17 
181. Run a live Lighthouse Accessibility audit when that capability is available; with Chrome DevTools MCP, use `lighthouse_audit`. Use mobile navigation mode for a general public page or snapshot mode when reloading would lose authenticated or user-created state.
192. Use failed audit nodes to localize the relevant component or template instead of searching the whole repository for generic patterns.
203. Inspect a rendered accessibility-tree snapshot for names, roles, states, landmarks, and heading structure; with Chrome DevTools MCP, use `take_snapshot`. Exercise the affected flow with the keyboard.
214. Fix the source, then re-run the same audit and manual interaction.
22 
23If 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.
24 
25## WCAG Principles: POUR
26 
27| Principle | Description |
28|-----------|-------------|
29| **P**erceivable | Content can be perceived through different senses |
30| **O**perable | Interface can be operated by all users |
31| **U**nderstandable | Content and interface are understandable |
32| **R**obust | Content works with assistive technologies |
33 
34## Conformance levels
35 
36| Level | Requirement | Target |
37|-------|-------------|--------|
38| **A** | Minimum accessibility | Must pass |
39| **AA** | Standard compliance | Should pass (legal requirement in many jurisdictions) |
40| **AAA** | Enhanced accessibility | Nice to have |
41 
42---
43 
44## Perceivable
45 
46### Text alternatives (1.1)
47 
48**Images require alt text:**
49```html
50<!-- ❌ Missing alt -->
51<img src="chart.png">
52 
53<!-- ✅ Descriptive alt -->
54<img src="chart.png" alt="Bar chart showing 40% increase in Q3 sales">
55 
56<!-- ✅ Decorative image (empty alt) -->
57<img src="decorative-border.png" alt="" role="presentation">
58 
59<!-- ✅ Complex image with longer description -->
60<figure>
61 <img src="infographic.png" alt="2024 market trends infographic"
62 aria-describedby="infographic-desc">
63 <figcaption id="infographic-desc">
64 <!-- Detailed description -->
65 </figcaption>
66</figure>
67```
68 
69**Icon buttons need accessible names:**
70```html
71<!-- ❌ No accessible name -->
72<button><svg><!-- menu icon --></svg></button>
73 
74<!-- ✅ Using aria-label -->
75<button aria-label="Open menu">
76 <svg aria-hidden="true"><!-- menu icon --></svg>
77</button>
78 
79<!-- ✅ Using visually hidden text -->
80<button>
81 <svg aria-hidden="true"><!-- menu icon --></svg>
82 <span class="visually-hidden">Open menu</span>
83</button>
84```
85 
86**Visually hidden class:**
87```css
88.visually-hidden {
89 position: absolute;
90 width: 1px;
91 height: 1px;
92 padding: 0;
93 margin: -1px;
94 overflow: hidden;
95 clip: rect(0, 0, 0, 0);
96 white-space: nowrap;
97 border: 0;
98}
99```
100 
101### Color contrast (1.4.3, 1.4.6)
102 
103| Text Size | AA minimum | AAA enhanced |
104|-----------|------------|--------------|
105| Normal text (< 18px / < 14px bold) | 4.5:1 | 7:1 |
106| Large text (≥ 18px / ≥ 14px bold) | 3:1 | 4.5:1 |
107| UI components & graphics | 3:1 | 3:1 |
108 
109```css
110/* ❌ Low contrast (2.5:1) */
111.low-contrast {
112 color: #999;
113 background: #fff;
114}
115 
116/* ✅ Sufficient contrast (7:1) */
117.high-contrast {
118 color: #333;
119 background: #fff;
120}
121 
122/* ✅ Focus states need contrast too (3:1 against background, WCAG 1.4.11) */
123:focus-visible {
124 outline: 2px solid currentColor;
125 outline-offset: 2px;
126}
127```
128 
129**Don't rely on color alone:**
130```html
131<!-- ❌ Only color indicates error -->
132<input class="error-border">
133<style>.error-border { border-color: red; }</style>
134 
135<!-- ✅ Color + icon + text -->
136<div class="field-error">
137 <input aria-invalid="true" aria-describedby="email-error">
138 <span id="email-error" class="error-message">
139 <svg aria-hidden="true"><!-- error icon --></svg>
140 Please enter a valid email address
141 </span>
142</div>
143```
144 
145### Media alternatives (1.2)
146 
147```html
148<!-- Video with captions -->
149<video controls>
150 <source src="video.mp4" type="video/mp4">
151 <track kind="captions" src="captions.vtt" srclang="en" label="English" default>
152 <track kind="descriptions" src="descriptions.vtt" srclang="en" label="Descriptions">
153</video>
154 
155<!-- Audio with transcript -->
156<audio controls>
157 <source src="podcast.mp3" type="audio/mp3">
158</audio>
159<details>
160 <summary>Transcript</summary>
161 <p>Full transcript text...</p>
162</details>
163```
164 
165---
166 
167## Operable
168 
169### Keyboard accessible (2.1)
170 
171**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.
172 
173```html
174<!-- ❌ Non-interactive element with click only: not focusable, no keyboard activation -->
175<div class="card" onclick="handleAction()">Open</div>
176 
177<!-- ✅ Best: use a native button -->
178<button type="button" onclick="handleAction()">Open</button>
179```
180 
181```javascript
182// ✅ When you MUST use a non-interactive element (e.g. div with role="button"),
183// make it focusable AND handle keyboard activation. Do NOT add this to a native
184// <button> — Enter/Space already fire click, so you'd double-trigger.
185element.setAttribute('role', 'button');
186element.setAttribute('tabindex', '0');
187element.addEventListener('click', handleAction);
188element.addEventListener('keydown', (e) => {
189 if (e.key === 'Enter' || e.key === ' ') {
190 e.preventDefault();
191 handleAction();
192 }
193});
194```
195 
196**No keyboard traps.** Users must be able to Tab into and out of every component. Use the [modal focus trap pattern](references/A11Y-PATTERNS.md#modal-focus-trap) for dialogs—the native `<dialog>` element handles this automatically.
197 
198### Focus visible (2.4.7)
199 
200```css
201/* ❌ Never remove focus outlines */
202*:focus { outline: none; }
203 
204/* ✅ Use :focus-visible for keyboard-only focus */
205:focus {
206 outline: none;
207}
208 
209:focus-visible {
210 outline: 2px solid currentColor; /* inherits text color → already contrast-checked */
211 outline-offset: 2px;
212}
213 
214/* ✅ Or pick a brand color and verify ≥3:1 contrast against every background it lands on */
215button:focus-visible {
216 box-shadow: 0 0 0 3px rgba(0, 95, 204, 0.5);
217}
218```
219 
220### Focus not obscured (2.4.11) — new in 2.2
221 
222When 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.
223 
224```css
225/* ✅ Account for sticky headers when scrolling to focused elements */
226:target {
227 scroll-margin-top: 80px;
228}
229 
230/* ✅ Ensure focused items clear fixed/sticky bars */
231:focus {
232 scroll-margin-top: 80px;
233 scroll-margin-bottom: 60px;
234}
235```
236 
237### Skip links (2.4.1)
238 
239Provide a skip link so keyboard users can bypass repetitive navigation. See the [skip link pattern](references/A11Y-PATTERNS.md#skip-link) for full markup and styles.
240 
241### Target size (2.5.8) — new in 2.2
242 
243Interactive 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.
244 
245```css
246/* ✅ Minimum target size */
247button,
248[role="button"],
249input[type="checkbox"] + label,
250input[type="radio"] + label {
251 min-width: 24px;
252 min-height: 24px;
253}
254 
255/* ✅ Comfortable target size (recommended 44×44) */
256.touch-target {
257 min-width: 44px;
258 min-height: 44px;
259 display: inline-flex;
260 align-items: center;
261 justify-content: center;
262}
263```
264 
265### Dragging movements (2.5.7) — new in 2.2
266 
267Any action that requires dragging must have a single-pointer alternative (e.g., buttons, inputs). See the [dragging movements pattern](references/A11Y-PATTERNS.md#dragging-movements) for a sortable-list example.
268 
269### Timing (2.2)
270 
271```javascript
272// Allow users to extend time limits
273function showSessionWarning() {
274 const modal = createModal({
275 title: 'Session Expiring',
276 content: 'Your session will expire in 2 minutes.',
277 actions: [
278 { label: 'Extend session', action: extendSession },
279 { label: 'Log out', action: logout }
280 ],
281 timeout: 120000
282 });
283}
284```
285 
286### Motion (2.3)
287 
288```css
289/* Respect reduced motion preference */
290@media (prefers-reduced-motion: reduce) {
291 *,
292 *::before,
293 *::after {
294 animation-duration: 0.01ms !important;
295 animation-iteration-count: 1 !important;
296 transition-duration: 0.01ms !important;
297 scroll-behavior: auto !important;
298 }
299}
300```
301 
302---
303 
304## Understandable
305 
306### Page language (3.1.1)
307 
308```html
309<!-- ❌ No language specified -->
310<html>
311 
312<!-- ✅ Language specified -->
313<html lang="en">
314 
315<!-- ✅ Language changes within page -->
316<p>The French word for hello is <span lang="fr">bonjour</span>.</p>
317```
318 
319### Consistent navigation (3.2.3)
320 
321```html
322<!-- Navigation should be consistent across pages -->
323<nav aria-label="Main">
324 <ul>
325 <li><a href="/" aria-current="page">Home</a></li>
326 <li><a href="/products">Products</a></li>
327 <li><a href="/about">About</a></li>
328 </ul>
329</nav>
330```
331 
332### Consistent help (3.2.6) — new in 2.2
333 
334If 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.
335 
336### Form labels (3.3.2)
337 
338Every input needs a programmatically associated label. See the [form labels pattern](references/A11Y-PATTERNS.md#form-labels) for explicit, implicit, and instructional examples.
339 
340### Error handling (3.3.1, 3.3.3)
341 
342Announce 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](references/A11Y-PATTERNS.md#error-handling) for full markup and JS.
343 
344### Redundant entry (3.3.7) — new in 2.2
345 
346Don'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.
347 
348```html
349<!-- ✅ Auto-fill shipping address from billing -->
350<fieldset>
351 <legend>Shipping address</legend>
352 <label>
353 <input type="checkbox" id="same-as-billing" checked>
354 Same as billing address
355 </label>
356 <!-- Fields auto-populated when checked -->
357</fieldset>
358```
359 
360### Accessible authentication (3.3.8) — new in 2.2
361 
362Login flows must not rely on cognitive function tests (e.g., remembering a password, solving a puzzle) unless at least one of:
363- A copy-paste or autofill mechanism is available
364- An alternative method exists (e.g., passkey, SSO, email link)
365- The test uses object recognition or personal content (AA only; AAA removes this exception)
366 
367```html
368<!-- ✅ Allow paste in password fields -->
369<input type="password" id="password" autocomplete="current-password">
370 
371<!-- ✅ Offer passwordless alternatives -->
372<button type="button">Sign in with passkey</button>
373<button type="button">Email me a login link</button>
374```
375 
376---
377 
378## Robust
379 
380### ARIA usage (4.1.2)
381 
382**Prefer native elements:**
383```html
384<!-- ❌ ARIA role on div -->
385<div role="button" tabindex="0">Click me</div>
386 
387<!-- ✅ Native button -->
388<button>Click me</button>
389 
390<!-- ❌ ARIA checkbox -->
391<div role="checkbox" aria-checked="false">Option</div>
392 
393<!-- ✅ Native checkbox -->
394<label><input type="checkbox"> Option</label>
395```
396 
397**When ARIA is needed,** use the correct roles and states. See the [ARIA tabs pattern](references/A11Y-PATTERNS.md#aria-tabs) for a complete tablist example.
398 
399### Live regions (4.1.3)
400 
401Use `aria-live` regions to announce dynamic content changes without moving focus. See the [live regions pattern](references/A11Y-PATTERNS.md#live-regions-and-notifications) for markup and a `showNotification()` helper.
402 
403---
404 
405## Testing checklist
406 
407### Automated testing
408 
409Prefer a live Lighthouse audit that returns failing rendered nodes directly to the agent. With Chrome DevTools MCP, this is `lighthouse_audit`. Otherwise:
410 
411```bash
412# Lighthouse accessibility audit
413npx lighthouse https://example.com --only-categories=accessibility
414 
415# axe-core
416npm install @axe-core/cli -g
417axe https://example.com
418```
419 
420### Manual testing
421 
422- [ ] **Keyboard navigation:** Tab through entire page, use Enter/Space to activate
423- [ ] **Screen reader:** Test with VoiceOver (Mac), NVDA (Windows), or TalkBack (Android)
424- [ ] **Zoom:** Content usable at 200% zoom
425- [ ] **High contrast:** Test with Windows High Contrast Mode
426- [ ] **Reduced motion:** Test with `prefers-reduced-motion: reduce`
427- [ ] **Focus order:** Logical and follows visual order
428- [ ] **Target size:** Interactive elements meet 24×24px minimum
429 
430See the [screen reader commands reference](references/A11Y-PATTERNS.md#screen-reader-commands) for VoiceOver and NVDA shortcuts.
431 
432---
433 
434## Common issues by impact
435 
436### Critical (fix immediately)
4371. Missing form labels
4382. Missing image alt text
4393. Insufficient color contrast
4404. Keyboard traps
4415. No focus indicators
442 
443### Serious (fix before launch)
4441. Missing page language
4452. Missing heading structure
4463. Non-descriptive link text
4474. Auto-playing media
4485. Missing skip links
449 
450### Moderate (fix soon)
4511. Missing ARIA labels on icons
4522. Inconsistent navigation
4533. Missing error identification
4544. Timing without controls
4555. Missing landmark regions
456 
457## References
458 
459- [WCAG 2.2 Quick Reference](https://www.w3.org/WAI/WCAG22/quickref/)
460- [WAI-ARIA Authoring Practices](https://www.w3.org/WAI/ARIA/apg/)
461- [Deque axe Rules](https://dequeuniversity.com/rules/axe/)
462- [Web Quality Audit](../web-quality-audit/SKILL.md)
463- [WCAG criteria reference](references/WCAG.md)
464- [Accessibility code patterns](references/A11Y-PATTERNS.md)
465 
View all files on GitHub →

Details

Updated
Aug 24, 2026
License
MIT
Stars on the repo
★ 2,832
Checked
Source
addyosmani/web-quality-skills ↗
Creator
addyosmani · 31 listings
View creator

Similar skills

See all →
SkillImplement WCAG 2.2 compliant interfaces with mobileAccessibility compliancewshobson/agents · by wshobsonImplement WCAG 2.2 compliant interfaces with mobile accessibility, inclusive design patterns, and assistive technology support. Use when auditing accessibility, implementing ARIA patterns, building for screen readers, or ensuring inclusive user experiences.★ 39.9k GitHub starsMCPYou need comprehensive accessibility testingAccessibility testerVoltAgent/awesome-claude-code-subagents · by VoltAgentUse this agent when you need comprehensive accessibility testing, WCAG compliance verification, or assessment of assistive technology support.★ 25.2k GitHub starsSkillHelps your project comply with accessibility standardsjakubkrehel/skills · by jakubkrehelHelps your project comply with accessibility standards and best practices.★ 7.1k GitHub starsSkillRun a comprehensive WCAG accessibility audit coveringrampstackco/claude-skills · by rampstackcoRun a comprehensive WCAG accessibility audit covering perceivable, operable, understandable, and robust principles. Use this skill whenever the user wants to audit accessibility, review WCAG compliance, fix accessibility issues, prepare for accessibility certification, address an accessibility lawsuit risk, or systematically improve a site's accessibility. Triggers on accessibility audit, WCAG audit, a11y audit, accessibility compliance, ADA compliance, screen reader test, keyboard navigation, accessibility report, fix accessibility, axe scan. Also triggers when accessibility issues have been reported and need systematic remediation.★ 901 GitHub starsSkillDesign, build, audit, and harden websites and web apps soWeb checkupjoshguntarverdiyev/web-checkup · by joshguntarverdiyevDesign, build, audit, and harden websites and web apps so they ship distinctive, secure, fast, accessible, and discoverable instead of looking AI-template generated. Use when creating or redesigning a landing page, SaaS UI, dashboard, portfolio, docs or ecommerce site; when a UI looks generic or "AI-made"; for UX/UI review, mobile and tablet responsiveness, accessibility, security audits (secrets, auth, database rules, headers), performance and Core Web Vitals, SEO, metadata, Open Graph, structured data, AI-search visibility, logo/favicon/icon/asset work, code quality, privacy compliance, or a pre-launch check. Also use when the user asks "is this ready to ship?", "is this safe?", "why does this look generic?", or "audit my site". Not for backend-only work with no web surface, and not for live penetration testing of systems the user does not own.★ 1 GitHub starsPromptGenerate production-grade CSS typography that followsWeb typographyf/prompts.chat · by Ceyhun Enki Aksan (ceaksan)Generate production-grade CSS typography that follows professional typographic rules. Based on Butterick's Practical Typography. Details and other related prompts: https://ceaksan.gumroad.com/l/typography-system-prompt-packNew listing

More from addyosmani

SkillGuides stable API and interface designaddyosmani/agent-skills · by addyosmaniGuides stable API and interface design. Use when designing APIs, module boundaries, or any public interface. Use when creating REST or GraphQL endpoints, defining type contracts between modules, or establishing boundaries between frontend and backend.★ 98.7k GitHub starsSkillTests in real browsers via Chrome DevTools MCPBrowser testing with devtoolsaddyosmani/agent-skills · by addyosmaniTests in real browsers via Chrome DevTools MCP. Use when building or debugging anything that runs in a browser. Use when you need to inspect the DOM, capture console errors, analyze network requests, profile performance, or verify visual output with real runtime data. Requires the chrome-devtools MCP server to be configured.★ 98.7k GitHub starsSkillAutomates CI/CD pipeline setupCI/CD and Automationaddyosmani/agent-skills · by addyosmaniAutomates CI/CD pipeline setup. Use when setting up or modifying build and deployment pipelines. Use when you need to automate quality gates, configure test runners in CI, or establish deployment strategies.★ 98.7k GitHub starsSkillApply modern web development best practices for securityaddyosmani/web-quality-skills · by addyosmaniApply modern web development best practices for security, compatibility, and code quality. Use when asked to "apply best practices", "security audit", "modernize code", "code quality review", or "check for vulnerabilities".★ 2.8k GitHub starsSkillOptimize Core Web Vitals for better page experienceCore Web Vitals optimizationaddyosmani/web-quality-skills · by addyosmaniOptimize Core Web Vitals (LCP, INP, CLS) for better page experience using field and lab evidence. Use when asked to "improve Core Web Vitals", "fix LCP", "reduce CLS", "optimize INP", "page experience optimization", or "fix layout shifts".★ 2.8k GitHub starsSkillConducts multi-axis code reviewCode review and qualityaddyosmani/agent-skills · by addyosmaniConducts multi-axis code review. Use before merging any change. Use when reviewing code written by yourself, another agent, or a human. Use when you need to assess code quality across multiple dimensions before it enters the main branch.★ 98.7k GitHub stars