web-accessibility-audit

Accessibility Auditor

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "web-accessibility-audit" with this command: npx skills add oldwinter/skills/oldwinter-skills-web-accessibility-audit

Accessibility Auditor

Audit web applications for WCAG 2.0/2.1/2.2 compliance by identifying common violations and providing actionable remediation steps.

When to Use

  • User requests accessibility audit, a11y check, or WCAG compliance review

  • User mentions accessibility issues, screen readers, or keyboard navigation problems

  • User asks to check or improve accessibility for people with disabilities

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

12 Most Common WCAG Violations

Based on WebAIM Million (2021) research analyzing top 1M websites:

Low Color Contrast (WCAG 1.4.3) - 86.4% of sites

  • Text < 4.5:1 contrast ratio

  • Large text < 3:1 contrast ratio

  • UI components < 3:1

Missing/Inadequate Alt Text (WCAG 1.1.1) - 60.6% of sites

  • Images without alt attribute

  • Alt text with "image", "picture", "photo"

  • Empty alt on meaningful images

Missing Name, Role, or Value (WCAG 4.1.2)

  • Interactive elements without accessible names

  • Custom components without proper ARIA

  • Buttons, form fields, custom widgets

Keyboard Navigation Failures (WCAG 2.1.1)

  • Elements with onClick but not keyboard accessible

  • Missing focus indicators

  • Trapped keyboard focus

Unlabeled Form Controls (WCAG 1.3.1, 3.3.2) - 39.6% of sites

  • Inputs without <label> or aria-label

  • Labels not programmatically associated

Missing Language Attributes (WCAG 3.1.1) - 28.9% of sites

  • No lang attribute on <html>

  • Missing lang for foreign language passages

Improper Heading Structure (WCAG 1.3.1, 2.4.6)

  • Skipped heading levels (h1 → h3)

  • Multiple h1s or no h1

  • Empty headings

Empty Links or Poor Link Text (WCAG 2.4.4)

  • Links with "click here", "here", "read more"

  • Empty links or links with only icons

Missing/Improper Focus Indicators (WCAG 2.4.7)

  • CSS removing outline without replacement

  • Insufficient focus indicator contrast

Overuse/Misuse of ARIA (WCAG 4.1.2)

  • Unnecessary ARIA when native HTML works

  • Invalid ARIA attributes for roles

  • Required ARIA attributes missing

Inadequate Data Table Markup (WCAG 1.3.1)

  • Tables without <th> elements

  • Missing scope or headers attributes

Missing Media Captions (WCAG 1.2.1, 1.2.2)

  • Videos without captions/subtitles

  • Audio without transcripts

Audit Process

Phase 1: Automated Testing

Run ESLint (React/JSX projects):

npx eslint --ext .jsx,.tsx --no-ignore --format json . > .claude/skills/a11y-auditor/eslint-results.json 2>&1 || true

Or use helper script: .claude/skills/a11y-auditor/scripts/run-eslint.sh

Run Lighthouse (production/staging):

npx lighthouse https://example.com --only-categories=accessibility --output=json --output-path=./lighthouse-results.json

Check for axe-core integration:

grep -r "@axe-core|axe-core" package.json

Phase 2: Manual Code Inspection

Use grep patterns from references/grep-patterns.md to search for:

  • Missing alt text

  • Keyboard navigation issues

  • Color values for contrast checking

  • ARIA issues

  • Form labels

  • Heading structure

  • Language attributes

  • Poor link text

  • Media elements

See references/grep-patterns.md for complete pattern list.

Phase 3: Analyze & Prioritize

Group findings by severity using WCAG impact levels:

Critical (fix immediately):

  • Keyboard traps

  • No focus indicators

  • Missing form labels

  • Missing alt text on functional images

  • Insufficient color contrast on interactive elements

Serious (fix before launch):

  • Missing page language

  • Improper heading structure

  • Non-descriptive link text

  • Missing skip links

  • Auto-playing media

Moderate (fix soon):

  • Missing ARIA labels on icons

  • Inconsistent navigation

  • Missing error identification

  • Missing landmark regions

Phase 4: Manual Testing

Follow references/screen-reader-guide.md for:

  • Keyboard navigation testing

  • Screen reader testing (VoiceOver, NVDA, JAWS)

  • Zoom and reflow testing

  • High contrast mode testing

  • Reduced motion testing

WCAG Pattern Examples

Perceivable

Alt Text (1.1.1)

<!-- ❌ Missing alt --> <img src="chart.png">

<!-- ✅ Descriptive alt --> <img src="chart.png" alt="Bar chart showing 40% increase in Q3 sales">

<!-- ✅ Decorative (empty alt) --> <img src="decorative-border.png" alt="" role="presentation">

Color Contrast (1.4.3)

/* ❌ Low contrast (2.5:1) */ .low-contrast { color: #999; background: #fff; }

/* ✅ Sufficient contrast (7:1) */ .high-contrast { color: #333; background: #fff; }

Contrast requirements:

  • Normal text: 4.5:1 (AA), 7:1 (AAA)

  • Large text (18px+ or 14px+ bold): 3:1 (AA), 4.5:1 (AAA)

  • UI components: 3:1

Media Alternatives (1.2)

<video controls> <source src="video.mp4" type="video/mp4"> <track kind="captions" src="captions.vtt" srclang="en" label="English" default> </video>

Operable

Keyboard Navigation (2.1.1)

// ❌ Only click element.addEventListener('click', handleAction);

// ✅ Click + keyboard element.addEventListener('click', handleAction); element.addEventListener('keydown', (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); handleAction(); } });

Focus Visible (2.4.7)

/* ❌ Never remove focus */ *:focus { outline: none; }

/* ✅ Keyboard-only focus */ :focus-visible { outline: 2px solid #005fcc; outline-offset: 2px; }

Skip Links (2.4.1)

<body> <a href="#main-content" class="skip-link">Skip to main content</a> <header><!-- navigation --></header> <main id="main-content" tabindex="-1"> <!-- content --> </main> </body>

.skip-link { position: absolute; top: -40px; left: 0; background: #000; color: #fff; padding: 8px 16px; z-index: 100; }

.skip-link:focus { top: 0; }

Reduced Motion (2.3.3)

@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 --> <html>

<!-- ✅ Language specified --> <html lang="en">

<!-- ✅ Language changes --> <p>The French word for hello is <span lang="fr">bonjour</span>.</p>

Form Labels (3.3.2)

<!-- ❌ No label --> <input type="email" placeholder="Email">

<!-- ✅ Explicit label --> <label for="email">Email address</label> <input type="email" id="email" autocomplete="email">

<!-- ✅ With hint --> <label for="password">Password</label> <input type="password" id="password" aria-describedby="password-requirements"> <p id="password-requirements"> Must be at least 8 characters with one number. </p>

Error Handling (3.3.1)

<label for="email">Email</label> <input type="email" id="email" aria-invalid="true" aria-describedby="email-error"> <p id="email-error" role="alert"> Please enter a valid email address. </p>

Robust

ARIA Usage (4.1.2)

<!-- ❌ Unnecessary ARIA --> <button role="button">Submit</button>

<!-- ✅ Native HTML --> <button>Submit</button>

<!-- ✅ ARIA when needed (custom tabs) --> <div role="tablist" aria-label="Product information"> <button role="tab" aria-selected="true" aria-controls="panel-1"> Description </button> <button role="tab" aria-selected="false" aria-controls="panel-2" tabindex="-1"> Reviews </button> </div> <div role="tabpanel" id="panel-1" aria-labelledby="tab-1"> <!-- content --> </div>

Live Regions (4.1.3)

<!-- Polite (waits for pause) --> <div aria-live="polite" aria-atomic="true"> Status update </div>

<!-- Assertive (interrupts) --> <div role="alert" aria-live="assertive"> Error: Form submission failed </div>

Visually Hidden Text

.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; }

<button> <svg aria-hidden="true"><!-- icon --></svg> <span class="visually-hidden">Delete item</span> </button>

Output Format

Generate reports structured as:

Accessibility Audit Report

Summary

  • Total Issues: X
  • Critical: X | Serious: X | Moderate: X | Minor: X
  • WCAG Level: A, AA, or AAA
  • Automated Coverage: ~57% (manual testing required)

Critical Issues (Fix Immediately)

1. [Issue Name] - WCAG X.X.X

Severity: Critical
Impact: [Who is affected and how]
Affected: X elements

Locations:

  • path/to/file.tsx:123
  • path/to/file.tsx:456

Problem: [Brief description]

Fix:

// Before
&#x3C;div onClick={handleClick}>Click me&#x3C;/div>

// After
&#x3C;button onClick={handleClick}>Click me&#x3C;/button>

Why: [Accessibility principle]

Serious Issues

[Same format]

Moderate Issues

[Same format]

Testing Recommendations

- Manual keyboard testing (Tab, Enter, Escape)

- Screen reader testing (see references/screen-reader-guide.md)

- Automated testing setup (@axe-core/react or Lighthouse CI)

- Color contrast validation (WebAIM Contrast Checker)

Next Steps

[Prioritized action items]

---

## Tools &#x26; Resources

### Development Tools
- **eslint-plugin-jsx-a11y** - React/JSX static analysis (~37 rules)
- **axe-core DevTools** - Browser extension for runtime testing
- **Lighthouse** - Built into Chrome DevTools

### Testing Tools  
- **@axe-core/react** - Runtime accessibility testing
- **@axe-core/playwright** - E2E test integration
- **pa11y** - Automated command-line testing

### Manual Testing
- **WebAIM Contrast Checker** - https://webaim.org/resources/contrastchecker/
- **WAVE** - Browser extension for visual feedback
- **Screen readers** - NVDA (Windows), VoiceOver (macOS), JAWS

### Reference Docs
- `references/WCAG-criteria.md` - All WCAG 2.1 success criteria
- `references/ARIA-patterns.md` - Common ARIA patterns and examples
- `references/screen-reader-guide.md` - Testing commands and scenarios
- `references/grep-patterns.md` - Search patterns for code audits

### References
- [WebAIM Million](https://webaim.org/projects/million/) - Annual analysis of top 1M websites (violation statistics)
- [WCAG 2.1 Quick Reference](https://www.w3.org/WAI/WCAG21/quickref/) - Interactive WCAG guide
- [WAI-ARIA Authoring Practices](https://www.w3.org/WAI/ARIA/apg/) - Official ARIA patterns
- [Deque axe Rules](https://dequeuniversity.com/rules/axe/) - All axe-core rules explained
- [jsx-a11y Rules](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y#supported-rules) - ESLint accessibility rules

---

## Important Notes

- Automated tools catch 30-57% of issues; manual testing required
- Pages with ARIA average 41% more errors than without
- Always test with actual assistive technology when possible
- Focus on critical issues first (keyboard, screen readers, contrast)
- Document deliberate accessibility decisions
- Test on multiple browsers and devices
- Include users with disabilities in testing when possible

## Common Pitfalls to Avoid

1. Relying solely on automated testing
2. Using ARIA when native HTML suffices
3. Removing focus indicators
4. Using positive tabindex values
5. Color as only means of conveying information
6. Keyboard traps in modals/dialogs
7. Non-descriptive link text
8. Missing or incorrect heading hierarchy
9. Unlabeled form controls
10. Missing language attributes

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Security

audit-website

No summary provided by upstream source.

Repository SourceNeeds Review
Security

seo-audit

No summary provided by upstream source.

Repository SourceNeeds Review
Security

seo-aeo-audit

No summary provided by upstream source.

Repository SourceNeeds Review