An accessible design system without slowing delivery
Accessibility becomes expensive when it is a remediation project. Built into the component layer, it costs almost nothing per feature.
Key takeaways
- Fix accessibility once in the component, not once per screen.
- Keyboard traversal and focus visibility catch more real problems than colour contrast audits.
- Automated checks in CI stop regressions; they do not replace a keyboard pass.
How do you make accessibility cheap?
Put it in the component layer. When the button, input, dialog and menu primitives handle labelling, focus and keyboard interaction correctly, every feature built on them inherits that behaviour, and accessibility stops being a separate workstream with its own budget.
Remediation is what makes it expensive
An accessibility audit on a mature product returns a few hundred findings, most of which are the same five mistakes repeated across every screen. Fixing them screen by screen is a quarter of work with no feature output, which is why it keeps getting deferred.
Fixing them in the shared components is a week, and it closes the same findings everywhere at once.
What to enforce where
| Layer | Responsibility | Enforcement |
|---|---|---|
| Primitives | Roles, labels, focus, keyboard interaction | Reviewed once, covered by unit tests |
| Feature code | Meaningful text, heading order, form grouping | Automated checks in CI |
| Flows | Completable by keyboard and screen reader | Manual pass before release |
The keyboard pass finds what scanners miss
Once a quarter we take the three revenue flows and complete them without touching the mouse. Every time, it surfaces something no scanner reported: focus lost after a dialog closes, a filter that can be opened but not dismissed, a toast that announces nothing.
It takes about ninety minutes and it consistently produces the most valuable items on the accessibility backlog.
Keep the checks in the pipeline
Automated rules in CI are not a substitute for that pass, but they are excellent at preventing regressions. Missing form labels, invalid ARIA and contrast failures should never reach review twice.
The combination — accessible primitives, automated regression checks, quarterly keyboard pass — is what makes accessibility a default rather than a project.
Document the pattern, not the rule
Accessibility guidance written as a rule list gets read once. Written as patterns in the component documentation, it gets used every time someone builds a form.
Each primitive in our library carries a short usage note: what it handles, what the consumer still has to supply, and one example of getting it wrong. A developer building a filter panel does not need to know the specification; they need to know that the component manages focus and that they still have to provide an accessible name.
That framing is also what keeps the system honest over time. When a pattern is missing, someone builds a bespoke version, and a bespoke version in a pull request is a visible signal that the library has a gap — which is far easier to act on than a quarterly audit finding.
FAQFAQ
Frequently asked questions
About the author
Tom builds the front end: rendering strategy, performance budgets and accessible interfaces that hold up under real network conditions. He writes about treating Core Web Vitals as a revenue metric rather than a lint rule.
- Core Web Vitals
- Next.js and React
- Web accessibility
- Frontend architecture