ESC

Type to search the knowledge base.

Accessibility in Large Apps

System design for accessibility at scale — governance, design system primitives, CI checks, and runtime patterns.

intermediate4 min read
  • 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: none without 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

  1. Skip link to main content
  2. Route change focus — move focus to main heading (tabIndex={-1}) on navigation
  3. Document title updates per route
  4. Global live region for assertive/polite announcements (auth errors, cart adds)
  5. Landmark structure — one main, consistent nav
// 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; lang on 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-live spam (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

  1. Strict CI vs ship speed — start with high-signal rules; expand
  2. Central components vs flexibility — forks kill consistency
  3. Automated-only confidence — false safety
  4. 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.

Further reading