Design Systems · Development · WCAG

Building Accessibility Into Your Design System From Day One (Not Sprint Whatever)

  • Design Systems
  • Development
  • WCAG

Forty Screens, One Broken Dropdown

A product team ships forty screens built from a shiny new design system, proud of how fast the rollout went. Then a pre-launch accessibility audit lands, and the first finding stops everyone cold: the exact same custom dropdown component — no keyboard support, no proper labeling, focus that vanishes the moment it opens — is duplicated across all forty screens. Nobody checked accessibility before that dropdown became the reusable pattern every designer and engineer on the team now reaches for by default.

This is the specific danger — and, handled correctly, the specific opportunity — of a design system. It multiplies whatever it contains. A genuinely accessible base component gets its correctness applied everywhere it's reused, automatically, for free. An inaccessible one gets its flaws copy-pasted just as automatically, at the same scale, by teams who have no reason to suspect the "approved" component in the library has a problem. This is exactly why accessibility work is dramatically cheaper done once, at the design-system level, than fixed page by page after a launch.

Contrast Belongs in the Token Layer

Color tokens are usually one of the very first things a design system defines, which makes them one of the cheapest places to get accessibility right. Every text and background color pairing should be verified against 1.4.3 Contrast (Minimum) (Level AA) — a 4.5:1 ratio for normal text, 3:1 for large text — at the moment the token is defined, not after it's been used across hundreds of components.

The same discipline applies to non-text elements under 1.4.11 Non-text Contrast (Level AA), which requires a 3:1 ratio for UI component boundaries, icons, and other graphical objects that convey meaning or state — think input borders, toggle states, and icon buttons. Checking a contrast ratio once, when a color token is defined, is a five-minute task. Auditing every individual usage of that color across a mature product later is a multi-week one.

Build Custom Widgets on the APG, Not Guesswork

Interactive components — buttons, links, form controls — should be built on native HTML elements wherever a native element can do the job. A native <button> comes with keyboard support, focus handling, and semantics built in for free; a <div> styled to look like a button does not, and reproducing all of that correctly by hand is exactly the kind of work that gets skipped under deadline pressure.

Where a genuinely custom widget is needed — a combobox, a tabbed interface, a modal dialog, an accordion — it should follow the W3C's WAI-ARIA Authoring Practices Guide (APG). The APG is a public, actively maintained reference with example markup and documented expected keyboard behavior for essentially every common widget pattern a design system is likely to need. This removes the guesswork of "what keys should this dropdown respond to?" — a question every engineering team eventually answers differently and inconsistently if there's no shared reference, which is exactly how a design system ends up with three different custom dropdowns that all behave slightly differently and are all slightly broken.

Focus States Are a Design Token, Not a Per-Component Decision

2.4.7 Focus Visible (Level AA) requires that any component that can receive keyboard focus has a visible indicator when it does. This should be defined once, as a design-system-level token or shared style, so every component in the library inherits a consistent, visible focus treatment automatically. Left undefined at the system level, focus styling tends to end up as whatever each individual engineer's browser default happens to render — or worse, individually suppressed with outline: none by someone trying to "clean up" a visual design without realizing what they just removed. A shared focus token closes that gap permanently, for every component that uses it, rather than requiring a fix to be applied and re-applied component by component.

Form Components Should Bake In the Whole Pattern

Forms are one of the highest-value places to invest design-system-level accessibility work, because form failures directly block task completion — and because the same mistakes tend to repeat across every form in a product if the base component doesn't prevent them.

A shared form component should bake in:

  • Correct label association (1.3.1 Info and Relationships and 4.1.2 Name, Role, Value) — every input programmatically tied to its visible label, not just visually adjacent to it.
  • autocomplete attribute support (1.3.5 Identify Input Purpose, Level AA) — so common fields like name, email, and address can be understood and assisted by the browser and by assistive technology.
  • A standard, accessible error pattern (3.3.1 Error Identification and 3.3.3 Error Suggestion) with an ARIA live region built directly into the component, so a validation error is announced to a screen reader user automatically the moment it appears — rather than relying on each team that reuses the form component to remember to wire that up correctly on their own, which in practice means it gets forgotten regularly.

Target Size Is a Sizing Rule, Not a QA Checklist Item

2.5.8 Target Size (Minimum) (Level AA) requires interactive targets to be at least 24x24 CSS pixels, with a short, specific list of exceptions. This should be a baked-in minimum size and spacing rule applied to any tappable component in the library — buttons, icon buttons, list items with actions — set once at the component level, rather than something a designer checks manually, screen by screen, after the visual design is already finalized. Icon-only buttons are the most common place this gets missed, since an 18x18px icon with tight spacing can look perfectly fine in a design file and still fail the actual measurement.

Make It a Gate, Not a Suggestion

None of this holds if it isn't enforced as part of the actual review process. The most durable fix is procedural: add an accessibility checklist and a sign-off gate to the design-system component review process itself, sitting alongside visual QA and code review rather than as a separate, optional step that happens "later." Every new or meaningfully changed base component should be tested with keyboard-only navigation and at least one screen reader before it's marked "ready to use" in the library.

Treat any accessibility fix made to a shared component as the systemic win it actually is, not a one-off ticket closed and forgotten. Fixing the dropdown once, correctly, at the component level fixes it everywhere that component is used — including the twenty screens that haven't been built yet.

Get the Foundation Right Before It Multiplies

The team from the opening scenario didn't have a screen-by-screen accessibility problem. They had one broken component and forty copies of it. That's the real lesson of building accessibility into a design system: get it wrong once, at the foundation, and the cost multiplies with every team that trusts the library. Get it right once, and the same multiplication works in your favor instead.

If your design system's base components haven't had a real accessibility review, get one before the next fifty screens get built on top of them — it's the cheapest point in the process to fix what's broken.