Skip to content

accessibility/

Accessibility Is a Delivery Gate, Not a Cleanup Week

Andrei Bespamiatnov

Andrei Bespamiatnov

Author

Cleanup week is where a11y goes to die

I have been in the room where accessibility is scheduled after feature complete. The deck looks responsible. The queue looks infinite. Contrast bugs lose to a launch date, and keyboard users get the backlog.

The teams that actually ship accessible UI treat WCAG like they treat a red unit test: it can fail the build, and someone owns the red.

That shift is not cultural poetry. It is fixtures, commands, and a gate.

Put the rule next to the flow, not in a wiki

A wiki page named “WCAG checklist” will be stale before the next sprint.

What works:

  • A small set of rules the pipeline runs on every PR that touches UI.
  • The same rules in the browser you already use for E2E (for us that has been Cypress plus axe).
  • Failures attached to a flow: “submit answer,” “open settings,” “finish session” — not “the app in general.”

“The app in general” is how you get a 400-violation dump that nobody triages. A flow is something a developer can open and fix.

Custom commands beat one-off cy.injectAxe()

If every spec invents its own scan, you will get five definitions of “critical.”

I keep a short command layer:

  • Visit a page (or a state) the way a user does.
  • Scan with a documented tag set (wcag2a / wcag2aa, and only the rules you have agreed to enforce).
  • Assert with a message that names the flow, not the library.

That command is the product. Specs stay thin. When we raise the bar — more tags, fewer exceptions — we change one place.

Exceptions exist. A third-party canvas or a licensed grid will fail rules you cannot fix this month. Put those exceptions in a list with an owner and a review date. An unlabeled cy.configureAxe({ rules: { ... disable everything } }) is not an exception. It is surrender.

Contrast is a token problem

Most “we failed color contrast” reports are not a missing aria-label. They are a theme token that looked fine on a designer’s calibrated laptop.

If you have a dark theme and a light theme, scan both. Hosted UI (a panel inside another product) must scan against the host theme, not only your default.

I treat token files as the fix site. Patching one button to a magic hex because axe yelled is how you get a second violation on the next screen that used the same token.

Keyboard is a journey, not a tab index contest

Axe will not feel a trap. A person will.

For flows that matter, I still write a few explicit keyboard journeys: open the dialog, move through actions, close, land somewhere predictable. If the focus ring is outline: none without a replacement, that is a defect, not a style choice.

Visual parity work — making a new UI match a trusted old one — is where this bites. The old UI had a focus treatment you stopped seeing. The new one dropped it. Users who never used a mouse notice immediately.

Make the gate boring

A good gate has three properties:

  1. It is fast enough that people do not skip it locally.
  2. It fails with a URL and a rule id, not a screenshot of a wall of JSON.
  3. It is owned. A red a11y job is someone’s rotation, like a red unit test job.

I do not run the entire WCAG catalog on every commit on day one. I turn on a slice, get to green, then widen. A gate that is always red is not a gate. It is wallpaper.

What this is not

This is not a claim that automation replaces people with assistive technology. It does not. Screen-reader passes and cognitive reviews still need humans.

Automation’s job is to stop the boring regressions — contrast, missing names, broken labels — from eating the human session. If the machine cannot fail those, the human session becomes a scavenger hunt.

A starting kit

  • Pick one user flow you already test in Cypress.
  • Add one scan command with a tight rule set.
  • Run it in CI on that flow only.
  • Fix the tokens it finds.
  • Add the next flow when the first stays green for a month.

After a quarter you will have a practice. After a cleanup week you will have a slide.