#tooling#typescript#javascript

The Accessibility Bugs Our Test Suite Never Caught

· 3 min read

There is no shortage of articles about Astro. Most of them cover the happy path. This one is about what happened after the happy path ended.

Most of the complexity was accidental. Over the years we'd layered three different approaches to accessibility on top of each other, and each one made sense at the time.

How we got here

We had good intentions. We even had a document describing how accessibility should work. The trouble was that the document and the code had quietly gone their separate ways.

The first symptom was subtle. Nothing failed outright, but accessibility kept drifting in the wrong direction, and every fix seemed to make the next one harder.

How it works

Rather than a big-bang rewrite, we migrated one module at a time over about 4 weeks, keeping both paths alive behind a flag.

Stripped of the project-specific bits, it looks like this:

export function debounce<T extends (...args: any[]) => void>(fn: T, wait = 200) {
  let timer: ReturnType<typeof setTimeout> | undefined;
  return (...args: Parameters<T>) => {
    clearTimeout(timer);
    timer = setTimeout(() => fn(...args), wait);
  };
}

It's tempting to generalize this into a library. Resist that urge until you've needed it in at least three places.

A few things that helped along the way:

  • Write the migration guide before writing the migration.
  • Pair on the first few changes so the knowledge doesn't live in one head.
  • Agree on what "done" means before the first pull request.
  • Make the default the safe choice, not just the documented one.

Caveats

There are cases where this falls apart. If your team is very small or your traffic is very spiky, the extra moving parts may not pay for themselves.

None of this is free. The new approach is a bit more verbose, and newcomers occasionally ask why we don't just use Svelte for everything. That's a fair question with a boring answer: we tried, and it made accessibility harder to reason about.

Closing thoughts

Six months in, nobody on the team wants to go back. That's about the best review a change like this can get.

OP
Owen Patel
Frontend engineer in Austin. Writing about frontend engineering.