Compliance Alliance Charter Design System · v0.1
Foundations

Accessibility

Principle 05 says leave no one behind — so access isn't a coat of paint, it's the floor we build on. The target is WCAG 2.2 AA. Everything below is built into the system once, so every component inherits it.

Color is its own focus. This page covers keyboard, focus, screen-reader semantics, motion, and target size. Color-vision modes are already built (see Color vision); the full token-pair contrast audit is the remaining piece, held for a dedicated pass.

Built-in, system-wide

Four things every page gets for free, from the shared base layer.

Skip link

Press Tab on any page — "Skip to content" appears first and jumps past the nav.

Decorative icons

Every Lucide icon is aria-hidden — screen readers never announce decoration.

Reduced motion

prefers-reduced-motion collapses animations, transitions, and smooth scroll.

Landmarks

Banner, navigation, and main landmarks on every page for structured navigation.

Focus

A single, high-contrast focus ring (token --focus-ring) on every interactive element via :focus-visible — visible for keyboard users, quiet for mouse users.

the focus ring (shown applied)
Tab through this page to see it live

Overlays (modal, drawer, menu, omnibox) trap focus while open, close on Esc, and return focus to the trigger when dismissed.

Keyboard

Every interaction is reachable and operable from the keyboard, in a logical order.

KeyAction
Tab / Shift+TabMove forward / back between controls
Enter / SpaceActivate a button; toggle a checkbox, switch, or row
EscClose a modal, drawer, menu, or omnibox; cancel
Move within tabs, menus, radio groups, the tree, and a workflow's steps
Home / EndJump to first / last item in a list or menu
/Ctrl+KOpen the command omnibox from anywhere

Screen readers

Meaning is conveyed in the accessibility tree, not just visually.

  • Status is text, not just color or shape. A status dot reads "● Watch", not a bare hue — the word ships with it.
  • Icon-only controls carry an aria-label (close, more, settings, pager, theme) so they announce a purpose.
  • Live updates use live regions — toasts and inline banners are role="status" (aria-live="polite"); errors and overdue alerts are role="alert".
  • Visually-hidden text via the .sr-only utility supplies labels and context that don't need to be seen.
.sr-only — visible only to assistive tech
<button class="btn btn--icon" aria-label="More actions"><i data-lucide="ellipsis"></i></button> <label class="field__label">Bank name <span aria-hidden="true">*</span><span class="sr-only">(required)</span></label> <div class="toast" role="status" aria-live="polite">…</div>

ARIA patterns by component

The roles and attributes each interactive component ships with.

ComponentRoles & attributes
Modal / dialogrole="dialog" · aria-modal="true" · aria-labelledby + aria-describedby · focus trapped · Esc closes · focus returns
Tabsrole="tablist" / tab · aria-selected · arrow-key navigation · panel role="tabpanel"
Menurole="menu" / menuitem · arrow keys · Esc closes · focus returns to trigger
Search / omniboxrole="combobox" · aria-expanded · aria-controls a listbox of options · arrow keys + Enter
Treerole="tree" / treeitem · aria-expanded on parents · arrow keys
Accordionheader is a button with aria-expanded + aria-controls for its panel
Progress / meterrole="progressbar" · aria-valuenow / aria-valuemin / aria-valuemax
Toast / bannerrole="status" (polite) for info/success; role="alert" for errors & overdue
Breadcrumbs<nav aria-label="Breadcrumb"> · current page marked aria-current="page"
Step navigationcompleted/active/upcoming exposed via aria-current="step" + visually-hidden status

Forms

Every field's label, hint, and error are programmatically tied to the input.

accessible field markup
<label class="field__label" for="rt">Routing number</label> <input class="input" id="rt" aria-invalid="true" aria-describedby="rt-err"> <span class="field__error" id="rt-err">Must be 9 digits.</span>
  • for / id tie label to control — the label is clickable and announced.
  • aria-describedby connects hints and errors so they're read with the field.
  • aria-invalid marks the error state; required is real, not just a "*".
  • Checkboxes, radios, and switches wrap their input in the label — associated by construction.

Motion & target size

Reduced motion

Spinners, skeletons, the agentic-streaming shimmer, and all transitions stop when the OS requests reduced motion.

Target size

Interactive targets meet the 24px minimum; default controls are 30–38px with comfortable hit areas.

Color & contrast

Color-vision modes are now live — opt-in palettes (red-green & tritanopia) that swap the status tokens, with a built-in CVD simulator. See Color vision. Still on the list for a dedicated pass: a full token-pair contrast audit (AA/AAA) and pattern/texture fallbacks for status.