Accessibility
What the system handles for you, and what stays with you.
The target
Every Bridge screen meets WCAG 2.2 level AA: usable with a keyboard, a screen reader, zoom, voice control and reduced motion.
What the system does, and what stays with you
| The package handles | You still handle |
|---|---|
| Keyboard, focus and screen-reader roles for every interactive component (through Base UI). | A clear label for every control. An icon-only button needs aria-label. |
| Contrast of every token pair, checked on every build. | Using tokens for their job, so the checked pairs are the pairs you ship. |
| A visible focus ring on every component. | A logical tab order: the order on screen is the order in the code. |
| Reduced motion for CSS animations. | Checking useReducedMotion() in Framer Motion animations. |
| Minimum target size (the smallest button is 28px). | Real headings in order, landmarks, and alt text for images that carry meaning. |
| Linking a field's help text and error to it. | Marking the optional fields with “(optional)”, never a red asterisk on required ones (Forms and validation). |
Rules
- Focus shows only for keyboard use (
focus-visible): a 2px ring with a 2px offset. Never remove it without a replacement. - Status is never color alone. Pair it with an icon or a word.
- Use the real element: a
<button>for actions, a link for navigation. Never a clickable<div>. - Dialogs trap focus, close on Escape and return focus to what opened them.
- Things that change on their own (a count updating, a save finishing) are announced through a polite live region.
- Tooltips use InfoHint / HoverTip, which work with keyboard focus. Never the browser's
titleattribute for an explanation. - Charts have a text summary (
role="img"with a title), and keyboard users can step through points with the arrow keys.
Pairs below 4.5:1
Every pair Bridge uses is on the Tokens page. These are the ones that fall short in at least one theme.
| Text | On | Used for | Light | Dark |
|---|---|---|---|---|
--text-disabled | --surface-primary | disabled text (exempt from contrast rules) | 2.00:1Fail | 2.72:1Fail |
white | --primary | why buttons don't fill with --primary | 6.98:1Pass | 3.79:1Fail |
white | --error | why buttons don't fill with --error | 4.41:1Fail | 2.78:1Fail |
Disabled text is exempt. White on --primary and --error are listed to show why buttons fill with the -solid tokens instead.
Before you ship a screen
- Tab through the whole screen with the mouse unplugged. Everything works, in a sensible order, with focus always visible.
- Turn on a screen reader and listen to the main path. Every control says what it is and what it does.
- Zoom to 200%. Nothing is cut off or overlaps.
- Turn on reduced motion. Nothing important is lost.
- Check dark mode and a 390px-wide screen.
Rules
Fill with -solid
Anything with white text on a colored fill uses --primary-solid or --danger-solid. The brand --primary and --error are for text, icons and focus rings; as fills they fail contrast (white on --error is 4.41:1).
Never by color alone
Status and meaning are never carried by color alone. A colored tag has a word; a status color comes with an icon or text; a chart says in words what it shows.
Every control has a name
Every control says what it does to a screen reader. An icon-only button carries an aria-label naming the action ("Close", not "X"); a group of filters or a table has a name; a tooltip is never the only name.
Focus always shows
Every control shows a visible ring when reached by keyboard (focus-visible). Never remove an outline without drawing a ring in its place.
Not decided yet
Until these are settled, follow Bridge OS as it is today.
- Touch target size. Bridge OS's smallest control is 28px tall, which clears WCAG's 24px minimum. The frontend-developer skill asks for 44px on touch screens. Pick one rule for phones.
- Focus ring color on dark surfaces. The accessibility skill says to switch to a white ring on dark backgrounds; Bridge OS uses the blue ring at 40% in both themes. Check its 3:1 contrast in dark mode before deciding.
Known gaps
Where Bridge OS code differs from this page today. Follow the page, not the gap.
- Bridge OS sets
:focus-visible { outline: none }on everything, so any control without its own ring shows no focus at all. The package doesn't ship that rule. - The accessibility skill's contrast table is out of date: white on Royal is 6.98:1 (not 4.8:1) and Ruby on white is 4.41:1 (not 4.0:1). It also calls 16px bold "large text"; WCAG's large text is 24px, or about 19px bold.
Sources
- accessibility-specialist skill (WCAG 2.2 AA target, focus, keyboard, ARIA, forms, motion).
- Bridge OS
components.md→ Button accessibility, IconButton (requiredaria-label), InfoHint (the one tooltip), ConfirmDialog (Escape and backdrop disabled while busy). - Bridge OS
DESIGN.md→ Charts (keyboard and live-region pattern). - Contrast computed from the package stylesheet on every build.