Accessibility Engineering
Build accessible UIs: WCAG 2.2 compliance, ARIA roles and properties, keyboard navigation, screen reader testing, and automated accessibility audits.
Web accessibility ensures people with disabilities can use your product. WCAG 2.2 defines the standards; correct HTML semantics, ARIA, and keyboard support are the implementation. Accessibility is a legal requirement in many jurisdictions and improves UX for everyone.
Semantic HTML first - most accessibility is free with correct element choices. Add ARIA only when HTML semantics are insufficient. Test with keyboard and a real screen reader (NVDA/VoiceOver). Run automated axe audits in CI. Accessibility is not an afterthought - build it in from the start.
Workflow
- Use semantic HTML correctlySemantic HTML gives browsers and assistive technologies free behavior - focus management, roles, and keyboard support.
- Apply ARIA correctlyARIA fills gaps where HTML semantics don't cover the interaction pattern.
- Implement keyboard navigationKeyboard users (including screen reader users) need full keyboard access to all interactive elements.
- Test with screen readersAutomated tools catch 30-40% of issues - screen reader testing catches the rest.
- Automate accessibility checks in CIAutomated checks catch regressions before they reach production.
Output Format
Semantic HTML (landmarks, headings, native elements), ARIA for custom widgets (role + state + properties), keyboard focus management with skip links, NVDA + VoiceOver test, axe-playwright in CI.
Examples
Modal focus management: `function Modal({ isOpen, onClose, triggerRef }) { const modalRef = useRef<HTMLDivElement>(null); useEffect(() => { if (isOpen) { const prev = document.activeElement as HTMLElement; modalRef.current?.focus(); return () => prev?.focus() } }, [isOpen]); return isOpen ? <div role="dialog" aria-modal="true" aria-labelledby="modal-title" ref={modalRef} tabIndex={-1}><h2 id="modal-title">Title</h2>...content...<button onClick={onClose}>Close</button></div> : null }`Live region: `function Toast({ message }) { return <div aria-live="polite" aria-atomic="true" className="toast">{message}</div> }` // message changes → screen reader announces itaxe test: `test.describe("accessibility", () => { test("homepage", async ({ page }) => { await page.goto("/"); const results = await new AxeBuilder({ page }).withTags(["wcag2a","wcag2aa","wcag21aa"]).analyze(); const violations = results.violations; expect(violations, violations.map(v => `${v.id}: ${v.description}`).join("\n")).toHaveLength(0) }) })`Edge Cases & Gotchas
- Color contrast: WCAG AA requires 4.5:1 for normal text, 3:1 for large text (18pt/14pt bold). Check with browser DevTools color contrast tool or axe. Don't rely on color alone to convey information
- Focus visible: WCAG 2.2 requires visible focus indicators. Never `outline: none` without an alternative. Custom focus styles: `:focus-visible { outline: 3px solid #6366f1; outline-offset: 2px }`
- Accessible SVGs: decorative SVGs need `aria-hidden="true"`. Informative SVGs need `role="img"` and `aria-label` or a `<title>` element inside
When to Break These Rules
- There are no legitimate reasons to skip accessibility. Legal requirements (ADA, EN 301 549, EAA 2025) and ethical obligations apply universally. Prioritize which WCAG criteria to tackle first based on impact, but never deprioritize entirely.
Reference Files
WCAG 2.2: https://www.w3.org/TR/WCAG22/ARIA Authoring Practices: https://www.w3.org/WAI/ARIA/apg/axe-core: https://github.com/dequelabs/axe-coreWebAIM: https://webaim.org/