FSD Frontend System Design

Part IV β€” The Reach Β· Lesson 8.6

Accessibility Tools

In one lineAutomation finds about a third of real issues β€” know exactly which third, and cover the rest by hand.

Where you've seen itA perfect Lighthouse accessibility score on a checkout that traps keyboard users in a modal.

  • Time14 min
  • DiagramTool coverage matrix β€” what each tool can and cannot see
  • Chapter8 Β· Accessibility

Diagram

diagram
COVERAGE MATRIX β€” the honest picture

  issue type                      automated   manual
  ─────────────────────────────────────────────────────
  missing alt attribute              βœ“          βœ“
  colour contrast (static)           βœ“          βœ“
  missing form label                 βœ“          βœ“
  invalid ARIA / bad roles           βœ“          βœ“
  duplicate ids, heading order       βœ“          βœ“
  ─────────────────────────────────────────────────────
  alt text that is WRONG             βœ—          βœ“
  tab order that makes no sense      βœ—          βœ“
  focus lost after an action         βœ—          βœ“
  live region never announces        βœ—          βœ“
  keyboard trap in a modal           βœ—          βœ“
  screen-reader flow is nonsense     βœ—          βœ“
  contrast over an image             βœ—          βœ“

  ~30–40% automated Β· the remainder needs a human
diagram
THE TOOLBOX β€” pick per stage

  DESIGN     Figma contrast plugins        catch the palette early
  DEV        axe DevTools extension        instant per-page audit
             Chrome a11y tree panel        see name/role/state
  TEST       jest-axe / axe-playwright     fail the build (4.7)
             Testing Library role queries  a11y as a side effect (4.8)
  CI         Lighthouse CI                 score gate per route
  MANUAL     keyboard only                 30 seconds, biggest payoff
             VoiceOver (Cmd+F5) / NVDA     the real experience
             browser zoom to 200%          reflow and truncation
diagram
AUTOMATED CHECK IN A TEST β€” cheap, permanent

  import { axe } from 'jest-axe';

  test('has no automatic a11y violations', async () => {
    const { container } = render(<Checkout />);
    expect(await axe(container)).toHaveNoViolations();
  });

How it works

  1. Shift left: contrast in design, axe in the editor, jest-axe in unit tests, Lighthouse in CI.
  2. Gate the build on automated violations so regressions can't merge (see 4.7 for the pattern).
  3. Do the keyboard pass manually on every new flow β€” thirty seconds, and it finds what automation structurally cannot.
  4. Learn one screen reader. VoiceOver on macOS with four commands is enough to catch most announcement bugs.
  5. Test at 200% zoom and 320px width β€” reflow failures are common and entirely invisible to automated checks.

Trade-offs

ToolStrengthBlind spot
axe / jest-axeFast, precise, CI-friendlySemantics, order, flow
LighthouseOne score, easy to trackSame limits, plus sampling
Screen readerThe real experienceSlow, needs practice
Keyboard passHighest value per minuteDoesn't cover announcements
User testingFinds what all of the above missCost and scheduling

Interview angle

"Lighthouse gives us 100. Are we accessible?"

  • No β€” automated tools cover roughly a third of the criteria, mostly static markup issues.
  • They can't judge whether alt text is correct, whether tab order makes sense, or whether focus survives an action.
  • Pair automation in CI with a manual keyboard and screen-reader pass on each new flow.

Recap

  • Automation catches static markup issues; humans catch flow, order, and meaning.
  • Keyboard-only testing is the highest-value 30 seconds in the whole discipline.
  • Gate the automatable part in CI so it never regresses.