Files
2025-11-29 18:20:21 +08:00

21 KiB
Raw Permalink Blame History

Accessibility Review

Performs comprehensive accessibility (a11y) audit focusing on WCAG compliance, screen reader compatibility, keyboard navigation, and inclusive design principles.

Parameters

Received from router: $ARGUMENTS (after removing 'accessibility' operation)

Expected format: scope:"review-scope" [depth:"quick|standard|deep"] [level:"A|AA|AAA"]

Workflow

1. Parse Parameters

Extract from $ARGUMENTS:

  • scope: What to review (required) - components, pages, features
  • depth: Review thoroughness (default: "standard")
  • level: WCAG compliance level (default: "AA")

WCAG Compliance Levels

  • Level A: Minimum accessibility (basic compliance)
  • Level AA: Standard accessibility (recommended target)
  • Level AAA: Enhanced accessibility (gold standard)

2. Gather Context

Identify UI Components:

# Find frontend components
find . -name "*.tsx" -o -name "*.jsx" -o -name "*.vue" -o -name "*.svelte" | head -20

# Check for accessibility tooling
cat package.json | grep -E "axe|pa11y|lighthouse|eslint-plugin-jsx-a11y"

# Look for ARIA usage
grep -r "aria-" --include="*.tsx" --include="*.jsx" --include="*.html" | head -20

# Check for role attributes
grep -r 'role=' --include="*.tsx" --include="*.jsx" --include="*.html" | head -20

3. Semantic HTML Review

Proper HTML Structure:

  • Semantic HTML elements used (<header>, <nav>, <main>, <footer>, <article>, <section>)
  • Headings in logical order (h1 → h2 → h3, no skipping)
  • Lists use <ul>, <ol>, <dl> appropriately
  • Tables use <table>, <th>, <caption> properly
  • Forms use <form>, <label>, <fieldset>, <legend>
  • Buttons use <button> (not styled divs)
  • Links use <a> with href attribute

Document Structure:

  • Single <h1> per page describing main content
  • Landmark regions defined (<header>, <nav>, <main>, <aside>, <footer>)
  • Skip to main content link present
  • Page has meaningful <title>
  • Language attribute on <html> element

Code Examples - Semantic HTML:

<!-- ❌ BAD: Non-semantic markup -->
<div class="header">
  <div class="nav">
    <div class="nav-item" onclick="navigate('/home')">Home</div>
    <div class="nav-item" onclick="navigate('/about')">About</div>
  </div>
</div>
<div class="main-content">
  <div class="title">Welcome</div>
  <div class="text">Content here</div>
</div>

<!-- ✅ GOOD: Semantic HTML -->
<header>
  <nav aria-label="Main navigation">
    <ul>
      <li><a href="/home">Home</a></li>
      <li><a href="/about">About</a></li>
    </ul>
  </nav>
</header>
<main>
  <h1>Welcome</h1>
  <p>Content here</p>
</main>
<!-- ❌ BAD: Incorrect heading hierarchy -->
<h1>Main Title</h1>
<h3>Subsection</h3> <!-- Skipped h2! -->
<h2>Another Section</h2> <!-- Wrong order! -->

<!-- ✅ GOOD: Logical heading order -->
<h1>Main Title</h1>
<h2>Section</h2>
<h3>Subsection</h3>
<h2>Another Section</h2>
<h3>Another Subsection</h3>

4. ARIA (Accessible Rich Internet Applications)

ARIA Attributes:

  • ARIA used only when semantic HTML insufficient
  • ARIA roles appropriate and correct
  • ARIA properties accurately reflect state
  • ARIA labels provide meaningful descriptions
  • Dynamic content changes announced

Common ARIA Patterns:

  • Buttons: role="button" with aria-pressed for toggles
  • Dialogs: role="dialog", aria-modal="true", aria-labelledby
  • Tabs: role="tablist", role="tab", role="tabpanel", aria-selected
  • Menus: role="menu", role="menuitem", aria-haspopup
  • Alerts: role="alert" or aria-live="assertive"
  • Loading: aria-busy="true", aria-live="polite"

ARIA Best Practices:

  • First rule of ARIA: Don't use ARIA (prefer semantic HTML)
  • ARIA doesn't change behavior, only semantics
  • ARIA attributes are valid and supported
  • Required ARIA attributes present
  • ARIA properties reflect current state

Code Examples - ARIA:

// ❌ BAD: Div as button without proper ARIA
<div onClick={handleClick} className="button">
  Click me
</div>

// ✅ GOOD: Proper button element (no ARIA needed)
<button onClick={handleClick}>
  Click me
</button>

// ✅ ACCEPTABLE: Div with complete button semantics
<div
  role="button"
  tabIndex={0}
  onClick={handleClick}
  onKeyDown={(e) => e.key === 'Enter' && handleClick()}
  aria-label="Click me"
>
  Click me
</div>
// ❌ BAD: No ARIA for custom dropdown
<div className="dropdown">
  <div onClick={toggle}>Menu</div>
  {isOpen && (
    <div className="menu">
      <div onClick={handleOption1}>Option 1</div>
      <div onClick={handleOption2}>Option 2</div>
    </div>
  )}
</div>

// ✅ GOOD: Proper ARIA for dropdown
<div className="dropdown">
  <button
    aria-haspopup="true"
    aria-expanded={isOpen}
    onClick={toggle}
  >
    Menu
  </button>
  {isOpen && (
    <ul role="menu">
      <li role="menuitem">
        <button onClick={handleOption1}>Option 1</button>
      </li>
      <li role="menuitem">
        <button onClick={handleOption2}>Option 2</button>
      </li>
    </ul>
  )}
</div>
// ❌ BAD: Loading state not announced
{isLoading && <div className="spinner">Loading...</div>}

// ✅ GOOD: Loading state announced to screen readers
{isLoading && (
  <div role="status" aria-live="polite">
    <span className="spinner" aria-hidden="true"></span>
    <span className="sr-only">Loading...</span>
  </div>
)}

5. Keyboard Navigation

Keyboard Accessibility:

  • All interactive elements keyboard accessible
  • Tab order is logical and follows visual order
  • Focus indicators visible and clear
  • No keyboard traps (can always tab away)
  • Skip links for keyboard users
  • Shortcuts don't conflict with browser/screen reader
  • Custom controls have keyboard support

Keyboard Interactions:

  • Enter/Space activates buttons and links
  • Arrow keys navigate lists and menus
  • Escape closes dialogs and menus
  • Tab moves to next element
  • Shift+Tab moves to previous element
  • Home/End navigate to start/end

Focus Management:

  • Focus visible (no outline: none without alternative)
  • Focus moved appropriately (dialogs, route changes)
  • Focus restored when closing dialogs
  • Focus not lost during dynamic updates
  • Focus indicator meets contrast requirements (3:1)

Code Examples - Keyboard Navigation:

// ❌ BAD: No keyboard support for custom control
<div onClick={handleClick} className="custom-button">
  Click me
</div>

// ✅ GOOD: Full keyboard support
<div
  role="button"
  tabIndex={0}
  onClick={handleClick}
  onKeyDown={(e) => {
    if (e.key === 'Enter' || e.key === ' ') {
      e.preventDefault();
      handleClick();
    }
  }}
  className="custom-button"
>
  Click me
</div>
/* ❌ BAD: Removed focus indicator */
*:focus {
  outline: none; /* Never do this without alternative! */
}

/* ✅ GOOD: Enhanced focus indicator */
*:focus {
  outline: 2px solid #4A90E2;
  outline-offset: 2px;
}

/* ✅ BETTER: Visible focus, hidden for mouse users */
*:focus-visible {
  outline: 2px solid #4A90E2;
  outline-offset: 2px;
}
// ❌ BAD: Dialog doesn't trap focus
function Dialog({ isOpen, onClose, children }) {
  if (!isOpen) return null;

  return (
    <div className="dialog">
      <button onClick={onClose}>Close</button>
      {children}
    </div>
  );
}

// ✅ GOOD: Dialog with focus trap
function Dialog({ isOpen, onClose, children }) {
  const dialogRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (isOpen) {
      // Focus first focusable element
      const firstFocusable = dialogRef.current?.querySelector(
        'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
      );
      (firstFocusable as HTMLElement)?.focus();
    }
  }, [isOpen]);

  if (!isOpen) return null;

  return (
    <div
      ref={dialogRef}
      role="dialog"
      aria-modal="true"
      onKeyDown={(e) => e.key === 'Escape' && onClose()}
    >
      <button onClick={onClose}>Close</button>
      {children}
    </div>
  );
}

6. Screen Reader Compatibility

Screen Reader Considerations:

  • All content accessible to screen readers
  • Images have alt text (or marked decorative)
  • Form inputs have associated labels
  • Error messages announced
  • Dynamic content changes announced
  • Hidden content not read by screen readers
  • Reading order matches visual order

Text Alternatives:

  • Images have descriptive alt text
  • Decorative images have alt="" or aria-hidden="true"
  • Icon buttons have accessible names
  • SVG graphics have <title> and <desc>
  • Video/audio has captions and transcripts
  • Complex images have long descriptions

Form Accessibility:

  • Labels associated with inputs (<label for="..."> or wrapping)
  • Required fields indicated (required or aria-required)
  • Error messages associated with fields (aria-describedby)
  • Fieldsets group related inputs
  • Form validation errors announced
  • Help text associated with inputs

Code Examples - Screen Readers:

// ❌ BAD: No alt text
<img src="/logo.png" />

// ✅ GOOD: Descriptive alt text
<img src="/logo.png" alt="Company Logo" />

// ✅ GOOD: Decorative image
<img src="/decorative-border.png" alt="" />
<img src="/background.png" aria-hidden="true" />
// ❌ BAD: Icon button without accessible name
<button onClick={handleDelete}>
  <TrashIcon />
</button>

// ✅ GOOD: Icon button with accessible name
<button onClick={handleDelete} aria-label="Delete item">
  <TrashIcon aria-hidden="true" />
</button>

// ✅ ALSO GOOD: Visually hidden text
<button onClick={handleDelete}>
  <TrashIcon aria-hidden="true" />
  <span className="sr-only">Delete item</span>
</button>
// ❌ BAD: Form without labels
<input type="text" placeholder="Enter your name" />

// ✅ GOOD: Properly labeled form field
<label htmlFor="name">Name</label>
<input type="text" id="name" placeholder="Enter your name" />

// ✅ ALSO GOOD: Wrapping label
<label>
  Name
  <input type="text" placeholder="Enter your name" />
</label>
// ❌ BAD: Error not associated with field
<input type="email" id="email" />
{error && <div className="error">Invalid email</div>}

// ✅ GOOD: Error associated with field
<input
  type="email"
  id="email"
  aria-invalid={!!error}
  aria-describedby={error ? "email-error" : undefined}
/>
{error && (
  <div id="email-error" className="error" role="alert">
    Invalid email
  </div>
)}

7. Color and Contrast

Color Contrast (WCAG AA):

  • Normal text: 4.5:1 contrast ratio minimum
  • Large text (18pt+ or 14pt+ bold): 3:1 minimum
  • UI components: 3:1 contrast with adjacent colors
  • Focus indicators: 3:1 contrast with background
  • WCAG AAA: 7:1 for normal text, 4.5:1 for large text

Color Usage:

  • Information not conveyed by color alone
  • Color blind friendly palette
  • Links distinguishable without color (underline, icon)
  • Form validation errors not color-only
  • Charts/graphs have patterns or labels

Code Examples - Color and Contrast:

// ❌ BAD: Color only to indicate error
<input
  type="text"
  style={{ borderColor: hasError ? 'red' : 'gray' }}
/>

// ✅ GOOD: Multiple indicators for error
<input
  type="text"
  aria-invalid={hasError}
  aria-describedby={hasError ? "error-message" : undefined}
  style={{
    borderColor: hasError ? 'red' : 'gray',
    borderWidth: hasError ? '2px' : '1px'
  }}
/>
{hasError && (
  <div id="error-message" role="alert">
    <ErrorIcon aria-hidden="true" />
    This field is required
  </div>
)}
// ❌ BAD: Link only differentiated by color
<a href="/more" style={{ color: 'blue', textDecoration: 'none' }}>
  Read more
</a>

// ✅ GOOD: Link with underline
<a href="/more" style={{ color: 'blue', textDecoration: 'underline' }}>
  Read more
</a>

// ✅ ALSO GOOD: Link with icon
<a href="/more" style={{ color: 'blue' }}>
  Read more <ArrowIcon aria-hidden="true" />
</a>

8. Responsive and Adaptive Design

Viewport and Zoom:

  • Content adapts to viewport size
  • Text can be resized to 200% without loss of functionality
  • No horizontal scrolling at 320px width
  • Touch targets at least 44x44 pixels (mobile)
  • Pinch-to-zoom not disabled

Media Queries:

  • Reduced motion preferences respected
  • High contrast mode supported
  • Dark mode accessible
  • Print styles appropriate

Code Examples - Responsive:

/* ❌ BAD: Disables zoom */
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">

/* ✅ GOOD: Allows zoom */
<meta name="viewport" content="width=device-width, initial-scale=1">
/* ✅ GOOD: Respect reduced motion preference */
@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}
// ✅ GOOD: Touch targets sized appropriately
<button style={{
  minWidth: '44px',
  minHeight: '44px',
  padding: '12px'
}}>
  Click me
</button>

9. Multimedia Accessibility

Video Accessibility:

  • Captions for all audio content
  • Audio descriptions for visual content
  • Transcript provided
  • Controls keyboard accessible
  • Auto-play disabled or user-controlled

Audio Accessibility:

  • Transcripts provided
  • Visual indicators for audio cues
  • User can control volume and playback

Code Examples - Multimedia:

<!-- ✅ GOOD: Video with captions and transcript -->
<video controls>
  <source src="video.mp4" type="video/mp4">
  <track kind="captions" src="captions.vtt" srclang="en" label="English">
  <track kind="descriptions" src="descriptions.vtt" srclang="en" label="English">
</video>
<details>
  <summary>Video Transcript</summary>
  <p>[Full transcript here]</p>
</details>

10. Automated Testing

Run Accessibility Audits:

# Lighthouse audit
npx lighthouse https://your-site.com --only-categories=accessibility --view

# axe-core testing
npm install --save-dev @axe-core/cli
npx axe https://your-site.com

# pa11y testing
npm install --save-dev pa11y
npx pa11y https://your-site.com

# ESLint accessibility plugin (React)
npm install --save-dev eslint-plugin-jsx-a11y

Manual Testing:

  • Test with keyboard only (no mouse)
  • Test with screen reader (NVDA, JAWS, VoiceOver)
  • Test with browser zoom at 200%
  • Test in high contrast mode
  • Test with CSS disabled
  • Test on mobile devices

Review Depth Implementation

Quick Depth (10-15 min):

  • Semantic HTML check
  • Alt text verification
  • Form label check
  • Keyboard navigation test
  • Automated audit (Lighthouse)

Standard Depth (30-45 min):

  • Complete WCAG AA checklist
  • ARIA usage review
  • Keyboard navigation thorough test
  • Focus management review
  • Color contrast check
  • Screen reader spot checks

Deep Depth (60-90+ min):

  • Complete WCAG AAA checklist
  • Comprehensive screen reader testing
  • Keyboard-only navigation of entire scope
  • Color blindness simulation
  • Reduced motion testing
  • High contrast mode testing
  • Mobile accessibility testing
  • Automated testing suite

Output Format

# Accessibility Review: [Scope]

## Executive Summary

**Reviewed**: [What was reviewed]
**Depth**: [Quick|Standard|Deep]
**WCAG Level Target**: [A|AA|AAA]
**Accessibility Rating**: [Excellent|Good|Needs Work|Poor]

### Overall Assessment
**[Compliant|Partially Compliant|Non-Compliant] with WCAG [Level]**

[Brief explanation]

### Priority Actions
1. [Critical a11y issue 1]
2. [Critical a11y issue 2]

---

## Critical Issues 🚨

**[Must fix for basic accessibility]**

### [Issue 1 Title]
**File**: `path/to/component.tsx:42`
**WCAG Criterion**: [X.X.X - Criterion Name - Level A/AA/AAA]
**Issue**: [Description of accessibility barrier]
**Impact**: [How this affects users]
**Affected Users**: [Screen reader users, keyboard users, low vision users, etc.]
**Fix**:

```tsx
// Current (inaccessible)
[problematic code]

// Accessible implementation
[fixed code]

Testing: [How to verify the fix]

[Repeat for each critical issue]


High Priority Issues ⚠️

[Should fix for good accessibility]

[Similar format for high priority issues]


Medium Priority Issues

[Consider fixing for enhanced accessibility]

[Similar format for medium priority issues]


Low Priority Issues 💡

[Nice to have for optimal accessibility]

[Similar format for low priority issues]


Accessibility Strengths

  • [Good practice 1 with examples]
  • [Good practice 2 with examples]
  • [Good practice 3 with examples]

WCAG 2.1 Compliance Summary

Level A (Minimum)

Criterion Status Notes
1.1.1 Non-text Content / ⚠️ / [Details]
1.3.1 Info and Relationships / ⚠️ / [Details]
1.3.2 Meaningful Sequence / ⚠️ / [Details]
2.1.1 Keyboard / ⚠️ / [Details]
2.1.2 No Keyboard Trap / ⚠️ / [Details]
2.4.1 Bypass Blocks / ⚠️ / [Details]
3.1.1 Language of Page / ⚠️ / [Details]
4.1.1 Parsing / ⚠️ / [Details]
4.1.2 Name, Role, Value / ⚠️ / [Details]
Criterion Status Notes
1.4.3 Contrast (Minimum) / ⚠️ / [Details]
1.4.5 Images of Text / ⚠️ / [Details]
2.4.5 Multiple Ways / ⚠️ / [Details]
2.4.6 Headings and Labels / ⚠️ / [Details]
2.4.7 Focus Visible / ⚠️ / [Details]
3.1.2 Language of Parts / ⚠️ / [Details]
3.2.3 Consistent Navigation / ⚠️ / [Details]
3.3.3 Error Suggestion / ⚠️ / [Details]
3.3.4 Error Prevention (Legal) / ⚠️ / [Details]

Level AAA (Enhanced) - Optional

[If deep review includes AAA]


Detailed Accessibility Analysis

🏗️ Semantic HTML

Overall: [Excellent|Good|Needs Work]

Strengths:

  • [Well-structured areas]

Issues:

  • ⚠️ [Semantic HTML issues with file references]

Heading Structure:

h1: [Page title]
  h2: [Section 1]
    h3: [Subsection]
  h2: [Section 2]

🎯 ARIA Usage

Overall: [Appropriate|Overused|Underused]

Proper ARIA:

  • [Good ARIA usage examples]

ARIA Issues:

  • ⚠️ [ARIA problems with file references]

⌨️ Keyboard Navigation

Overall: [Fully Accessible|Partially Accessible|Not Accessible]

Tab Order: [Logical|Needs Work]

Keyboard Support:

  • [Components with full keyboard support]
  • ⚠️ [Components with keyboard issues]

Focus Management: [Good|Needs Improvement]

📢 Screen Reader Compatibility

Tested with: [NVDA|JAWS|VoiceOver|Narrator]

Screen Reader Experience: [Excellent|Good|Poor]

Issues Found:

  • ⚠️ [Screen reader issues]

Missing Alternatives:

  • ⚠️ [Missing alt text, labels, etc.]

🎨 Color and Contrast

Contrast Ratio Analysis:

Element Foreground Background Ratio WCAG AA WCAG AAA
Body text [Color] [Color] [X:1] / /
Links [Color] [Color] [X:1] / /
Buttons [Color] [Color] [X:1] / /

Color Usage: [Accessible|Issues Found]

📱 Responsive and Mobile

Mobile Accessibility: [Excellent|Good|Needs Work]

Touch Target Sizes: [Adequate|Too Small]

Zoom Support: [Enabled|Disabled]


Testing Results

Automated Testing

Lighthouse Score: [X/100]

axe-core Results:

  • Critical issues: [X]
  • Serious issues: [X]
  • Moderate issues: [X]
  • Minor issues: [X]

Manual Testing

Keyboard-Only Navigation: [Pass|Fail] - [Details]

Screen Reader Testing: [Pass|Fail] - [Details]

Zoom to 200%: [Pass|Fail] - [Details]

High Contrast Mode: [Pass|Fail] - [Details]


Recommendations

Immediate (This Week)

  • [Critical fix 1]
  • [Critical fix 2]

Short-term (This Month)

  • [High priority fix 1]
  • [High priority fix 2]

Long-term (This Quarter)

  • [Strategic improvement 1]
  • [Strategic improvement 2]

Resources

Testing Tools:

  • Lighthouse (Chrome DevTools)
  • axe DevTools (browser extension)
  • WAVE (browser extension)
  • Screen reader (NVDA, JAWS, VoiceOver)

Guidelines:


Review Metadata

  • Reviewer: 10x Fullstack Engineer (Accessibility Focus)
  • Review Date: [Date]
  • WCAG Level: [A|AA|AAA]
  • A11y Issues: Critical: X, High: X, Medium: X, Low: X
  • Compliance Status: [Compliant|Partially Compliant|Non-Compliant]

## Agent Invocation

This operation MUST leverage the **10x-fullstack-engineer** agent with accessibility expertise.

## Best Practices

1. **Semantic HTML First**: Use native elements before ARIA
2. **Test with Real Users**: Automated tools catch ~30-40% of issues
3. **Keyboard First**: If keyboard works, most other things will follow
4. **Don't Assume**: Test with actual assistive technology
5. **Progressive Enhancement**: Start accessible, add features
6. **Inclusive Design**: Consider all users from the beginning