Practical Guide to Building an Accessible Design System: Component Specs, Token Design, WCAG 2.1 AA Acceptance Criteria, and Ongoing Governance
Summary (Key Points First)
- Accessibility is stronger when it’s protected by systems, not by individual effort. Turning it into a design system is the shortest path.
- The key to success is to build in this order: (1) design tokens (color/spacing/type/focus) → (2) component specs (interaction/states/copy) → (3) acceptance criteria (testable) → (4) operations (governance).
- Trying to jump straight to AAA exhausts teams. Start by embedding the most accident-prone WCAG 2.1 AA areas (forms, modals, tabs, menus, tables, video) into standard components.
- This article includes a component spec template, token examples, how to write accessibility acceptance criteria, operating rules, and a 5-minute smoke test.
Intended readers (examples): UI/UX designers, frontend engineers, PMs/directors, QA, accessibility specialists, standardization leads at agencies, multi-product ops teams
Accessibility level: aiming for WCAG 2.1 AA compliance (including continuous-improvement operations)
1. Introduction: Accessibility Becomes Easier When You Standardize It
The more carefully you try to do accessibility “the right way,” the more it tends to depend on individual grit and experience.
“How should we announce errors in this form?” “Where should focus return after a modal closes?” “How do we layer meaning beyond color?”—if you start from zero every time, time and cost rise, and quality swings whenever the person in charge changes.
That’s where an accessible design system shines.
You bake accessibility requirements into tokens (color/spacing/focus) and components (buttons/forms/modals) from the beginning. Then, even as products grow, pages multiply, and updates ship, the “kindness” is far less likely to break.
This guide is not just ideals—it’s written to be practical and operational, from design through governance.
2. The Big Picture: Build an Accessible Design System in Four Layers
Standardizing accessibility is easiest when you stack it in this order:
2.1 Layer 1: Design Tokens
- Colors (background/text/link/border/focus)
- Typography (size/line-height/weight)
- Spacing (padding/margins)
- Radius, shadows, borders
- Motion (intensity and “reduce motion” settings)
Goal: Fix the foundations for not only consistency, but also contrast, focus visibility, and target size.
2.2 Layer 2: Component Specifications
- Structure (HTML/ARIA basics)
- Interaction (keyboard behavior, focus transitions)
- States (hover/focus/disabled/error/selected)
- Copy rules (labels, help text, error text)
- Edge cases (loading, empty states, zero results)
Goal: Keep the experience consistent even when implementers change.
2.3 Layer 3: Acceptance Criteria
Define behavior in terms of outcomes, not just “WCAG numbers.”
Examples:
“Checkout can be completed using Tab only.” “Focus moves to the error summary.” “Esc closes and focus returns to the trigger.”
Goal: Make reviews non-subjective and give QA and engineering shared language.
2.4 Layer 4: Operations & Governance
- Change management (breaking changes, versioning)
- Audits (quarterly checks on representative screens)
- Support intake (accessibility contact point)
- Education (onboarding, checklists)
Goal: Shift from “we tried once” to “we can keep it safe forever.”
3. Token Design: Embed Accessibility Requirements From the Start
3.1 Color Tokens: Move From “Manual Checks” to “Built-In Safety”
Color is flexible—and therefore easy to break. A strong approach is to define color tokens by purpose:
--color-bg(background)--color-fg(body text)--color-muted(secondary text)--color-link(links)--color-border(borders)--color-focus(focus ring)--color-danger(error)--color-success(success)
Then explicitly document these token-level assumptions:
- Body text contrast is ≥ 4.5:1 (normal text)
- Large text contrast is ≥ 3:1
- Non-text (borders, icons, focus) contrast is ≥ 3:1
- Links must not rely on color alone (layer with underline, etc.)
3.2 Focus Tokens: Make Visible Focus a Default Feature
If focus rings are left to “each product’s taste,” they get removed.
So lock them in as tokens.
:root{
--focus-color: #FF9900;
--focus-width: 3px;
--focus-offset: 3px;
}
:focus-visible{
outline: var(--focus-width) solid var(--focus-color);
outline-offset: var(--focus-offset);
}
@media (prefers-contrast: more){
:focus-visible{ outline-width: 4px; }
}
3.3 Spacing & Target Size: Make “Clickability” With Padding
For buttons and checkboxes, “tappable area” matters more than visuals.
- Rule of thumb: ~44px height equivalent (especially on mobile)
- Ensure the hit target includes padding (don’t make only the text clickable)
3.4 Motion: Default to “Gentle” Movement
Skeletons and loading animations can increase cognitive load or motion sickness.
- Default: slower, lower contrast, no flashing
- Respect
prefers-reduced-motion: reduce(stop or significantly reduce)
4. Component Specifications: Turn Accessibility Into a Blueprint
Here is a reusable “spec shape” you can apply to every component.
4.1 Recommended Spec Template (Sections)
- Purpose: what the component is for
- Structure: base HTML elements; ARIA assumptions if used
- States: default / hover / focus / disabled / error / selected
- Keyboard behavior: Tab, arrows, Enter/Space, Esc, Home/End
- Focus management: initial focus, return focus, trapping rules
- Copy rules: labels, help text, how to write errors
- Responsive behavior: narrow-screen behavior
- Prohibited patterns: common failure cases
- Acceptance criteria: testable statements
- Examples: minimal implementation, good vs bad examples
When every component uses the same template, reviews become dramatically easier.
5. Standard Specs for High-Impact Components (Where It Pays Off Most)
5.1 Button
Structure
- Use
<button>by default (don’t build clickable divs) - Icon-only buttons must have an
aria-label
Keyboard
- Tab to focus
- Enter/Space activates
Acceptance criteria (examples)
- The button can be activated by keyboard
- Focus is visible (in both light and dark themes)
- Disabled uses the
disabledattribute, not just appearance
Example
<button type="button">Save</button>
<button type="button" aria-label="Close">
<img src="close.svg" alt="">
</button>
5.2 Form Fields (TextField / Select / Checkbox)
(Forms are high-risk, so standardization has the biggest payoff.)
Structure
- Always connect
labelandfor - Link hints via
aria-describedby - Errors use
aria-invalid="true"+ associate error text
Copy rules
- Errors must state: “where / why / how to fix”
- Required/optional must be explicit in the label (don’t rely on color alone)
Acceptance criteria (examples)
- A visible label exists and the field name is clear in screen readers
- When errors occur, an error summary appears and focus can move to the first error
autocompleteis appropriate (email, address, name, etc.)
Example
<div class="field">
<label for="email">Email (required)</label>
<input id="email" type="email" autocomplete="email"
aria-describedby="email-hint email-err"
aria-invalid="true">
<p id="email-hint">Example: example@example.com</p>
<p id="email-err" class="error" role="alert">The format is invalid.</p>
</div>
5.3 Modal (Dialog)
Structure
- Prefer native
<dialog>if possible; otherwise implement withrole="dialog" - Make background inert (
inertwhere supported; provide fallbacks)
Focus management
- On open: move focus to the first actionable element
- Tab cycles within the modal (trap)
- Esc closes
- On close: return focus to the trigger
Acceptance criteria (examples)
- While open, focus does not move to background elements
- Esc closes and focus returns to the original trigger button
- The dialog title is announced (name is provided)
5.4 Tabs and Menus
Standard rules
- Tab: move between regions; Arrow keys: move within a region (roving tabindex)
- Home/End: jump to first/last
- Expose selection state (e.g.,
aria-selected)
Acceptance criteria (examples)
- Arrow keys move to adjacent tabs
- The selected tab is identifiable in screen reader output
- Showing/hiding panels does not break layout or semantics
5.5 Table
(A powerful “standard component,” especially paired with your prior article.)
Structure
- Header cells use
th - Use
scopeby default; for complex tables, useheaders/idor split tables - Use
captionto describe the table’s purpose
Acceptance criteria (examples)
- When navigating cells with a screen reader, headers are clear
- On mobile, information is not lost (e.g., horizontal scroll instead of truncation)
5.6 Loading and Notifications (Status/Alert)
Standard rules
- Critical errors use
role="alert" - Success/completion uses
role="status"(avoid excessive interruption) - Spinners are
aria-hidden="true"and text like “Loading…” is provided
Acceptance criteria (examples)
- Loading state is understandable via text
- Motion stops or is significantly reduced with
prefers-reduced-motion
6. Writing Acceptance Criteria: Prefer “Outcome-Based” Over Just WCAG IDs
Acceptance criteria are the language that creates team alignment.
If you list WCAG IDs only, teams often ask “So what exactly do we test?” The following format works well.
6.1 Recommended Acceptance Criteria Format
- Context: which screen/component
- Action: what the user does (Tab, arrows, Enter, Esc, etc.)
- Expected result: what should happen (focus, announcement, state change)
- Exceptions: document any exceptions (embedded third-party content, etc.)
Example (Modal)
- Action: Press Enter on the Settings button to open the modal
- Expected: Focus moves to the first actionable element inside the modal
- Action: Press Esc
- Expected: The modal closes and focus returns to the Settings button
This makes designers, developers, and QA speak the same language.
7. Design Review vs Implementation Review: What to Check Where
7.1 Design Review (Figma etc.)
- Contrast (text/links/non-text)
- Focus ring visibility (including on busy backgrounds)
- States (hover/focus/disabled/error/selected)
- Touch targets (~44px)
- Copy (labels, help, error wording)
- Not relying on color alone (layer with icons/text)
7.2 Implementation Review
- Prefer native elements (button, a, input)
- Landmarks and heading hierarchy
- Can the flow be completed by keyboard only?
- ARIA correctness (too much ARIA is also a failure)
- Focus transitions (modal/menu/error states)
8. The 5-Minute Smoke Test: Make a “Ritual” in the Design System
A shared minimum test suite, enforced at the component level, prevents regressions.
- Core flows can be completed using Tab only
- Focus is visible (light/dark themes)
- Modal: open → interact → Esc → focus returns
- Forms: label + required indicator + error summary + per-field error association
- Meaning doesn’t rely on color alone (links, errors, states)
- No breakage at 200% zoom (except tables/code as noted)
- Motion is reduced with
prefers-reduced-motion - Screen readers can identify name/role/state at minimum
9. Operations & Governance: Keep the Design System “Used and Maintained”
9.1 Change Management (Versioning)
- Breaking changes (e.g., modal API change) = major version
- Small enhancements (copy additions, minor improvements) = minor/patch
- Write “what improved” first in release notes (helps adoption)
9.2 Exceptions (When You Truly Can’t Comply)
You can’t make exceptions disappear. The key is to standardize how exceptions are handled:
- Exception request (reason, impact, alternatives, planned fix)
- Add a deadline (avoid permanent exceptions)
- Link to accessibility statements/contact paths (prevent abandonment)
9.3 Roles (Minimal Setup)
- Owner: decides policy and priority
- Maintainers: update components and docs
- Reviewers: check acceptance criteria
- Support contact: collects pain points and turns them into improvements
You can start small—but with zero roles, it will inevitably decay.
10. Value by Role (Concrete Benefits)
- Designers: less uncertainty; standardized states/focus/copy speed up creation
- Engineers: standardized ARIA and focus-management patterns reduce regressions
- QA: outcome-based criteria make verification reproducible
- PM/Ops: quality stays stable as products grow; accountability and trust accumulate
- Users: consistent interaction across screens; clear paths when something goes wrong
11. Accessibility Level Evaluation (What This Guide Achieves)
This guide focuses on design + operations that continuously meet WCAG 2.1 AA, aligning especially with:
- 1.1.1 Non-text content: standardizing icon/image handling
- 1.3.1 Info and relationships: structured forms/tables/headings/landmarks
- 1.4.1 Use of color / 1.4.3 Contrast / 1.4.11 Non-text contrast: enforced via tokens
- 1.4.10 Reflow: defined in responsive component specs
- 2.1.1 Keyboard: standardized component interaction
- 2.4.3 Focus order / 2.4.7 Focus visible: fixed via focus tokens + specs
- 3.3.x Input assistance: standardized error messaging and prevention patterns
- 4.1.2 Name, role, value: minimal correct ARIA usage
By including testing and governance, it aims not for “one-time compliance,” but for maintainable compliance.
12. Conclusion: Turn Kindness Into Components—and Into Team Strength
- Accessibility becomes powerful when embedded into tokens and components.
- Specs should bundle structure, interaction, states, copy, and acceptance criteria.
- Acceptance criteria should prioritize testable outcomes over WCAG IDs.
- Make the 5-minute smoke test a ritual to prevent regressions.
- Manage exceptions with requests and deadlines; don’t leave users behind.
- With operations and governance, accessibility endures and trust accumulates.
Accessibility is most beautiful when it’s not “special,” but part of everyday standards.
May your team’s “kindness” continue naturally alongside your product’s growth.
