Skip to content
2 min read465 words

Accessibility is a feature, not a chore

Retro games taught me more about interface design than any design system. Keyboard-first thinking, focus order, and designing for the player who can't see the screen.

I learned interface design in 1994, on a controller with two buttons. There was no back button. If a screen didn't communicate its options, you didn't get them.

That constraint produced a kind of clarity that a mouse will never force on you. I've been trying to get back to it ever since, in a different medium.

Constraints produce clarity

Two buttons means:

  • Every screen has a single obvious action.
  • State must be visible. There is no hover to reveal the affordance.
  • Nothing can be hidden behind a gesture you might not know about.

Keyboard navigation is the same constraint. A modal that only closes on a mouse click in the corner is a modal that traps half your users — and it turns out those users are also half your reviewers, your QA testers, and the person who uses a screen reader at work.

The checklist I actually run

Not a 100-item audit. Five things, every component:

1. Can you see the focus ring?

css
:focus-visible {
  outline: 3px solid var(--phos);
  outline-offset: 2px;
}

That's it. Never outline: none without replacing it with something at least as visible. The focus ring is not decoration; it is the only indication a keyboard user has of where they are.

2. Does the DOM order match the visual order?

If you reorder things with order:, grid-area, or absolute positioning, you've broken keyboard navigation — because Tab follows DOM order, not visual order.

3. Is there a skip link?

Long pages with a big nav are hostile to keyboard and screen reader users alike. One visually-hidden link at the top fixes it:

tsx
<a href="#main" className="sr-only focus:not-sr-only focus:fixed focus:top-4">
  Skip to content
</a>

4. Does motion respect the visitor?

css
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    transition-duration: 0.001ms !important;
  }
}

This is the whole implementation. It belongs in your global stylesheet, and it should exist whether or not you think you have animations worth removing.

5. Do the icons have names?

An icon-only button with no accessible name is a dead end for anyone not using a mouse. Every icon-only control on this site has an aria-label:

tsx
<PixelButton sprite="crt" aria-label="Open system settings" />

The arcade test

Here's the exercise I use. Load your page and try to complete its primary task using only:

  1. The keyboard
  2. The screen reader
  3. 200% browser zoom
  4. Windows High Contrast Mode

If you can't, you don't have an accessibility feature set — you have a visual design with some markup around it.

This site passes because the retro theme made it easy. Hard borders mean strong contrast. Square controls have unambiguous hit areas. There is no hover-only information, because there's no hover in the design language. Everything animates in discrete steps, so nothing is disorienting.

The most accessible design system I ever worked on was a Game Boy. It had four shades of green, no text scaling, and a screen you could read in sunlight. Nothing was optional and nothing was ambiguous.

Filed under JAN 18 '26

All posts →

Command palette

Search for a command to run