Most accessibility work is repetitive, because most interfaces are. The same button, the same field, the same dialog, rebuilt across forty templates by people who each solved it slightly differently and none of whom were wrong on purpose.
A design system collapses that. Get the button right and every button is right, on every page, for as long as the component survives. Get it wrong and you have shipped one defect everywhere at once, which is the half teams tend to underestimate.
So the question worth answering carefully is which parts of accessibility a component can actually hold, and which parts stay with whoever puts the components on a page. That line is sharper than it sounds, and W3C's own conformance rules draw it for you.
What a Component Can Carry
Some accessibility lives inside the component and stays fixed once it is fixed. This is the part worth spending real money on, because the return gets multiplied by every use.
- The right element. A button that renders a
button, a link that renders ana. Most of 4.1.2 Name, Role, Value is solved by that alone, because a native control brings its role, its focusability, its keyboard activation and its own state with it. - Focus styles. Defined once, visible against every surface the component can sit on, and hard to remove by accident.
- Keyboard behaviour. Arrow keys in a tab list, Escape in a dialog, and the rest of the patterns set out across our interface patterns. ARIA makes this a duty rather than a nicety: eight container roles, including tablist, listbox, menu, grid and tree, carry must-level focus management the moment you claim the role.
- State exposure.
aria-expanded,aria-selectedandaria-currentwired to the component's own state rather than left to whoever consumes it, so the attribute and the interface cannot drift apart. - Target size. Padding that meets the minimum by default, so nobody has to think about 2.5.8 Target Size at the point of use.
- Colour tokens that pass. If the tokens encode approved pairs rather than approved colours, a designer cannot assemble a failing combination. A palette of individually blessed colours gives no such guarantee, because contrast is a property of two colours together.
Make the accessible thing the easy thing
A component that needs an extra prop to be accessible will ship without it, under deadline, by somebody who meant well. Put the correct behaviour in the default and make the exception the thing that takes effort.
What It Cannot Carry
This is the half that gets forgotten, and it is the reason a system built entirely from well-made components still produces pages that fail an audit.
- Names. Your icon button component can require a label. It cannot know whether the label somebody passed is any good.
- Order. Components arrive in whatever sequence the page author placed them, and 2.4.3 Focus Order is written as a property of a page, so no component can satisfy it alone.
- Headings. A heading component takes a level. Whether the levels across a page form a sensible outline is a page decision every time.
- Meaning. Alt text, error wording, link text. All of it is content, and content is where a large share of findings live.
- Composition. Three well-built components nested wrongly can still let focus escape a dialog or produce a reading order that makes no sense.
- Anything inline. Target size has an exception for targets sitting inside a sentence, so a link component is exempt used inline and not exempt used as a standalone control. The component cannot know which it is.
Why the Name Is the Part Nothing Can Check
The first item on that list looks like an opinion. It is not, and there is a number behind it that settles the argument in one line.
Name, Role, Value carries fifteen automated test rules, more than any other criterion in the standard, and ten of them name it as the thing they test. Seven of those ten test whether a name exists. Not one of them reads the name and asks whether it describes the control. A button whose accessible name is the literal word button passes all seven.
So your CI can guarantee that every icon button in the library has a label. Nothing you can install will tell you the label says what the button does. That is the exact boundary this page is about, and it is why the contract documentation below is worth more than another linting rule. The full picture is on 4.1.2 Name, Role, Value.
The same shape holds across the standard. Of the 86 criteria in WCAG 2.2, 49 have no automated test rule written against them at all. Automated checks in a component pipeline cover the part of the standard machines can reach, which is real and which is not the whole job.
Conformance Belongs to Pages, Not Components
There is a normative answer to the question every design system team eventually asks, and it is short. WCAG says conformance is for full web pages only, and cannot be achieved if part of a page is excluded.
Which means a component library cannot be conformant. Not because it is not good, but because conformance is not the kind of thing a component can have. Your system can make conformance far cheaper to reach and it can never hold the claim on its own. Two more lines in the same section stretch that further. Every responsive variation of a page has to conform separately, so a component that behaves differently at a breakpoint owes the same answer at every breakpoint. And where a page is part of a process, such as a checkout, every page in that process has to conform for any of them to count.
Document the Contract, Not Just the Component
The most useful thing a system can add costs about two sentences per component. A short accessibility note saying what the component handles and what the consumer still owes.
"This dialog keeps focus inside itself, closes on Escape and returns focus where it came from. You have to give it an accessible name." That is it. And it heads off the most common misuse in the whole category, which is a developer assuming the component covered everything because it covered a lot.
Testing the System Rather Than the Pages
- Test each component on its own, in every state it has, because a story or an example per state makes the check cheap enough to repeat.
- Run automated checks against the component library in CI, which catches regressions where they are born rather than six templates downstream. The practical setup is in accessibility testing in CI.
- Test compositions as well as components, since that is where focus order and nesting problems appear and neither shows up in isolation.
- Keep testing real pages, because the system has no way of seeing how it is being used.
How It Drifts
A system that was accessible at launch rarely stays that way on its own, and it tends to go the same four ways.
| What happens | Why it matters |
|---|---|
| A team copies a component and edits it | The fix in the original never reaches the copy |
| An override removes the focus ring | One line of CSS undoes a system-wide guarantee |
| A new colour is added outside the palette | It has never been measured against anything |
| A one-off component ships "just for this page" | It carries none of the system's behaviour |
The defence is the same in all four cases. The system needs an owner and a review step, because good intentions do not survive a release schedule. The habits that keep it standing are in keeping a site accessible.
If You Are Starting One
Build the primitives first, and build them properly. Button, link, input, dialog, and the focus and colour tokens underneath all four. Those carry most of the weight, and getting them right early is far cheaper than retrofitting a system a hundred pages already depend on.
Commissioning an Audit of the System You Have
The brief is the part worth getting right, because a design system audit is scoped by a list of components rather than by a set of addresses, and that list is a decision somebody on your side has to make. Get it right and every finding is a defect fixed in one place rather than forty, which is why this tends to be the cheapest audit a product team ever buys.
Six Things to Settle Before You Ask for a Price
- The component list, in your own names for them. Not the public documentation's names, if your team calls the thing a Field Group. The list is the scope, so it is also the estimate.
- The states each component has. Default, hover, focus, disabled, invalid, loading, empty, open and closed. A component with seven of those is seven things to look at, and this is where an estimate built on a component count goes wrong in both directions.
- Where the library actually lives, and how somebody reaches it. A Storybook behind your VPN is invisible to any public scan, so the address and the access have to arrive with the brief rather than after it.
- The framework and the version your products are really on. A finding against a version nobody ships is a finding nobody can close. If two products are on different major versions, say so, because that is either two audits or one with a stated limit.
- Three or four real pages built from the system. Composition problems live nowhere else. Naming the pages up front is what lets a component audit say anything at all about how the components are being used.
- Who receives the tickets, and where. Findings written for a library maintainer read differently from findings written for a page owner, and the difference is worth more than it sounds.
What This Evidence Answers, and What It Does Not
Four questions bring people to this decision, and a system audit answers part of each one. Knowing which part is what stops a buyer paying for the wrong evidence.
| The question | What a system audit gives you | What it leaves open |
|---|---|---|
| Are our components correct? | A per-component result across the states you listed, with the fix at the source | Nothing about how the components are arranged on any given page |
| Do our pages conform? | A shorter list of page defects, because the repeating ones are already gone | The claim itself. Conformance is a property of pages, so it needs pages tested |
| Can we tell a customer our product is accessible? | Real evidence about the parts, which is a genuine and limited thing to say | Everything a completed conformance report asks about the assembled product |
| Where should the budget go first? | The defects that repeat, ranked by how many places they land in | Content, wording and order, which are page decisions no component reaches |
Which is why the sequence most teams should buy is the system first and the pages second, and the reason is arithmetic rather than preference. Finding a repeated defect once in the library costs less than finding it on twelve pages and then fixing it in the library anyway. What each package covers is on pricing, and the component list is agreed before anything is charged.
One thing to be clear about on both sides. We test and we write the findings. Your maintainers make the changes, because they own the library and they know what else depends on it, and we verify the result on a re-audit. Nobody should be editing your components except the people who have to live with them.