103
LVL 04 — SENIOR-IN-TRAININGSESSION 103DAY 103

ACCESSIBILITY AUDIT

🎫 PIXELCRAFT-089
Accessibility | 🟡 Medium | Priority: 🟠 High

An accessibility audit found 23 violations. Screen readers can't navigate the toolbar. Keyboard users can't access settings. Color contrast is insufficient. Fix to WCAG 2.1 AA. 23 violations → 0.
CONCEPTS.UNLOCKED
📋
WCAG 2.1
Web Content Accessibility Guidelines — the standard. Three conformance levels: A (minimum), AA (industry target), AAA (ideal). Most jurisdictions require AA. WCAG is legally binding under ADA and EAA.
🏛️
POUR Principles
Perceivable, Operable, Understandable, Robust. Can users perceive it? (alt text, contrast) Operate it? (keyboard) Understand it? (clear labels) Does it work with assistive tech? (semantic HTML)
🏷️
ARIA Attributes
Enhance HTML semantics for assistive tech. role="toolbar", aria-label, aria-checked, aria-live. Use when native HTML semantics aren't enough. First rule of ARIA: don't use ARIA if native HTML works.
⌨️
Keyboard Navigation
Every interactive element reachable by keyboard. Tab to navigate, Enter/Space to activate, Arrow keys within groups, Escape to dismiss. If you can't use it without a mouse, it's broken.
🎨
Color Contrast
Minimum 4.5:1 for normal text, 3:1 for large text. Gray text on light background = invisible to low-vision users. Check every color pair. Tools: axe DevTools, WebAIM Contrast Checker.
🎯
Focus Management
Where does focus go after a modal opens? After a page navigation? Focus must follow the user's attention. Trap focus inside modals. Return focus when modals close. Never lose the focus indicator.
HANDS-ON.TASKS
01
Run axe Audit — Baseline

Install the axe DevTools browser extension. Open PixelCraft → run the audit. Screenshot 23 violations. Categorize: keyboard (8), contrast (6), ARIA (5), focus (4). Fix them all.

02
Fix Keyboard Navigation
// Toolbar: keyboard navigable // with arrow keys function Toolbar({ tools, activeTool, onToolSelect }: ToolbarProps) { const handleKeyDown = ( e: React.KeyboardEvent, index: number ) => { if (e.key === 'ArrowDown') { e.preventDefault(); const next = (index + 1) % tools.length; document.getElementById( `tool-${tools[next].id}`) ?.focus(); } if (e.key === 'ArrowUp') { e.preventDefault(); const prev = (index - 1 + tools.length) % tools.length; document.getElementById( `tool-${tools[prev].id}`) ?.focus(); } }; return ( <nav role="toolbar" aria-label="Image editing tools"> {tools.map((tool, index) => ( <button key={tool.id} id={`tool-${tool.id}`} role="radio" aria-checked={ activeTool === tool.id} tabIndex={ activeTool === tool.id ? 0 : -1} onKeyDown={(e) => handleKeyDown(e, index)} onClick={() => onToolSelect(tool.id)}> <span aria-hidden="true"> {tool.icon}</span> <span className="sr-only"> {tool.name}</span> </button> ))} </nav> ); }
03
Screen Reader Announcements
// Announce filter changes to // screen readers <div role="status" aria-live="polite" className="sr-only"> {`Brightness set to ${brightness}`} </div> // aria-live="polite": // announces when idle (non-urgent) // aria-live="assertive": // announces immediately (errors) // sr-only class (Tailwind): // Visually hidden, but screen // readers can still read it.
04
Focus Management: Modals
function Modal({ isOpen, onClose, children }: ModalProps) { const closeRef = useRef<HTMLButtonElement>(null); const previousFocus = useRef<HTMLElement | null>(null); useEffect(() => { if (isOpen) { // Save current focus previousFocus.current = document.activeElement as HTMLElement; // Move focus into modal closeRef.current?.focus(); } else { // Return focus when closing previousFocus.current?.focus(); } }, [isOpen]); if (!isOpen) return null; return ( <div role="dialog" aria-modal="true" aria-label="Export settings"> <button ref={closeRef} onClick={onClose}> Close </button> {children} </div> ); }
Focus trap: when a modal is open, Tab should cycle within the modal, not escape to the page behind it. When the modal closes, focus returns to the element that opened it.
05
Fix Color Contrast & Re-Audit
// Fix: adjust all low-contrast text // ❌ Before: #999 on #fff = 2.85:1 // (fails AA for normal text) // ✅ After: #595959 on #fff = 7.0:1 // (passes AA and AAA) // Check with: WebAIM Contrast Checker // Target: 4.5:1 normal, 3:1 large // Re-run axe audit: // 23 violations → 0 violations ✅
06
Close the Ticket
git switch -c a11y/PIXELCRAFT-089-accessibility git add src/ git commit -m "Fix 23 a11y violations: WCAG 2.1 AA (PIXELCRAFT-089)" git push origin a11y/PIXELCRAFT-089-accessibility # PR → Review → Merge → Close ticket ✅
CS.DEEP-DIVE

Universal design benefits everyone.

The web was designed to be accessible from birth. Good accessibility IS good design. Every accessibility feature has mainstream benefits.

// "Curb cut effect":

Curb cuts
  Designed for: wheelchairs
  Used by: strollers, carts, bikes

Keyboard navigation
  Designed for: motor disabilities
  Used by: power users, developers

Captions
  Designed for: deaf users
  Used by: noisy/quiet environments

High contrast
  Designed for: low vision
  Used by: outdoor/bright sunlight

// Tim Berners-Lee:
// "The power of the Web is
// in its universality."

// WCAG compliance isn't just ethical
// — it's legally required (ADA, EAA)
// and improves SEO (search engines
// are basically screen readers).
"Accessibility Lab"
[A]Add @axe-core/playwright to E2E tests (from session 088). After each page navigation, run an accessibility audit. Fail the test if any A/AA violations are found. Accessibility regressions are caught in CI.
[B]Test with a real screen reader: enable VoiceOver (Mac) or NVDA (Windows). Navigate the entire app by keyboard + voice. Record yourself doing it. Note every point of confusion — fix them.
[C]Research: what is the "accessibility tree"? How does the browser convert HTML → accessibility tree → screen reader output? Use Chrome DevTools Accessibility tab to inspect PixelCraft's accessibility tree.
REF.MATERIAL
ARTICLE
W3C
The official WCAG checklist: every success criterion with techniques and examples. Filter by level (A, AA, AAA) and topic.
WCAGOFFICIALESSENTIAL
VIDEO
Fireship
Quick overview: WCAG, ARIA, semantic HTML, keyboard navigation, and screen readers. The essential accessibility intro.
A11YQUICK
ARTICLE
Deque Systems
The industry-standard accessibility testing tool: browser extension, CI integration, and developer API. Finds WCAG violations automatically.
AXETOOLINGESSENTIAL
ARTICLE
WebAIM
Check color contrast ratios against WCAG AA and AAA. Enter foreground and background colors, get instant pass/fail results.
CONTRASTTOOL
VIDEO
Google Chrome Developers
How screen readers work: DOM → accessibility tree → screen reader output. VoiceOver demo with practical navigation examples.
SCREEN READERTUTORIAL
// LEAVE EXCITED BECAUSE
PixelCraft is usable by everyone. Navigate the entire app with keyboard only. Screen readers announce every action. axe audit shows zero violations. This is professional, inclusive software.