Accessibility in Large Apps
System design for accessibility at scale — governance, design system primitives, CI checks, and runtime patterns.
- system-design
- interview
- architecture
- a11y
Scope the problem
Accessibility in a large app is not a one-time audit — it’s platform design: components, pipelines, ownership, and telemetry.
In scope:
- Design-system foundations (focus, contrast, semantics)
- App shell patterns (routing focus, announcements)
- CI and review gates
- Runtime monitoring and issue triage
- Team workflows
Out of scope unless asked: full WCAG legal analysis, assistive tech engine internals.
Assumptions: multi-team monorepo or multi-package design system; continuous delivery; web primary (call out RN differences if asked).
Goals & metrics
| Goal | Metric / signal |
|---|---|
| Conformance | WCAG 2.2 AA target on critical journeys |
| Prevention | lint/a11y CI failures block merge |
| Detection | production axe/RUM a11y? limited — prefer synthetic + user reports |
| UX | keyboard task success, SR smoke tests |
Architecture layers
┌─────────────────────────────────────────────────────────┐
│ Governance: standards, severity rubric, SLAs │
├─────────────────────────────────────────────────────────┤
│ Design system: tokens, components, patterns, docs │
├─────────────────────────────────────────────────────────┤
│ App shell: router focus, live regions, skip links │
├─────────────────────────────────────────────────────────┤
│ Product features: compose primitives; rare custom a11y │
├─────────────────────────────────────────────────────────┤
│ Verification: unit/RTL, cypress/playwright + axe, QA │
└─────────────────────────────────────────────────────────┘
Design system as the control plane
Tokens
- Color pairs meeting contrast; semantic names (
--text-danger) not raw hex in apps - Focus ring tokens mandatory; never
outline: nonewithout replacement - Motion tokens honor
prefers-reduced-motion
Components
| Primitive | Built-in behavior |
|---|---|
| Button / Link | correct element; disabled semantics |
| Modal | focus trap, escape, restore, aria-modal |
| Menu / Select | APG keyboard models |
| Form Field | label, error, aria-describedby wiring |
| Toast | live region politeness |
Rule: product teams don’t invent modals. If they need a new pattern, it graduates into the system with docs and tests.
API discipline
// Good: requires label
<IconButton aria-label="Close" onClick={...} />
// Bad: optional label that ships empty in prod
<IconButton onClick={...} />
TypeScript: ban unlabeled icon-only buttons via prop types (aria-label required when no children text).
App shell patterns
- Skip link to main content
- Route change focus — move focus to main heading (
tabIndex={-1}) on navigation - Document title updates per route
- Global live region for assertive/polite announcements (auth errors, cart adds)
- Landmark structure — one
main, consistentnav
// router effect
useEffect(() => {
document.title = title;
mainHeadingRef.current?.focus();
}, [location.pathname, title]);
Data & content
- i18n: translated strings can break truncation and reordering — design for expansion; avoid concatenation for SR sense
- User content: don’t assume language;
langon content islands when known - Media: captions/transcripts pipeline for uploads
- Charts: text summary + data table alternative
Verification pipeline
| Stage | Tooling | Gate |
|---|---|---|
| Authoring | eslint-plugin-jsx-a11y | CI error |
| Unit | Testing Library roles/names | PR |
| E2E | Playwright + axe-core | Critical flows |
| Visual | optional contrast checks | design changes |
| Manual | SR smoke (VoiceOver/NVDA) on release trains | checklist |
| Prod | issue tracker tags; support escalation | SLA by severity |
Automated tools catch ~30–40% of issues — say this out loud. Keyboard and SR pass remain required for P0 flows (auth, checkout, create content).
Severity rubric (example)
- P0: keyboard trap, unusable checkout, missing names on primary actions
- P1: contrast fail on primary UI, broken focus order
- P2: missing captions, minor label issues
Performance interaction
Accessibility and performance reinforce:
- Faster TTI → less “screen reader ready” wait
- Avoid aggressive
aria-livespam (perf + UX) - Virtualized lists need
aria-rowindex/ careful focus when rows recycle
Org & ownership
- Design system team owns primitives
- Feature teams own journey conformance
- A11y champion network reviews P0
- Budget time in roadmap — not “polish week” only
Tradeoffs
- Strict CI vs ship speed — start with high-signal rules; expand
- Central components vs flexibility — forks kill consistency
- Automated-only confidence — false safety
- Custom widgets for brand vs native elements
Interview close
Structure answer as: standards target → design system enforcement → shell focus management → CI/manual mix → ownership model. Give one concrete failure (modal without focus trap) and how the platform prevents recurrence.
Related on this site
- Accessible Modal Dialog
- Accessibility Interview Talking Points
- Design a Design System
- Internationalization Architecture