Accessibility
All 304 contrast checks pass across 2 brands and 2 themes. How we check
Contrast checks
AAA: text at 7:1 or moreAA: meets the pair's minimumFails: below the minimum
Text on surfaces
20 pairs, all pass20 pairs, all pass20 pairs, all pass20 pairs, all pass20 pairs, all pass in all 4
| Pair | Bridge light | Bridge dark | Ocean light | Ocean dark |
|---|---|---|---|---|
| text.default on bg.default | 16.49AAA | 16.69AAA | 13.99AAA | 16.69AAA |
| text.default on surface.default | 16.49AAA | 15.35AAA | 15.03AAA | 13.99AAA |
| text.default on surface.raised | 16.49AAA | 10.13AAA | 15.03AAA | 10.08AAA |
| text.default on surface.selected | 15.40AAA | 16.73AAA | 14.02AAA | 16.62AAA |
| text.default on surface.hover | 14.31AAA | 10.13AAA | 13.11AAA | 10.08AAA |
| text.muted on bg.default | 5.85AA | 7.60AAA | 4.88AA | 7.66AAA |
| text.muted on bg.subtle | 5.08AA | 6.99AA | 4.57AA | 6.42AA |
| text.muted on surface.default | 5.85AA | 6.99AA | 5.24AA | 6.42AA |
| text.muted on surface.raised | 5.85AA | 4.61AA | 5.24AA | 4.62AA |
| text.muted on surface.hover | 5.08AA | 4.61AA | 4.57AA | 4.62AA |
| text.link on surface.default | 8.87AAA | 10.49AAA | 5.15AA | 9.69AAA |
| text.link on bg.default | 8.87AAA | 11.40AAA | 4.79AA | 11.56AAA |
| text.signal on surface.default | 8.87AAA | 10.49AAA | 7.38AAA | 9.69AAA |
| text.signal on signal.subtle | 7.73AAA | 9.59AAA | 6.44AA | 9.61AAA |
| text.inverse on surface.inverse | 16.49AAA | 15.55AAA | 15.03AAA | 15.65AAA |
| text.muted on feedback.neutral.bg | 5.08AA | 4.61AA | 4.57AA | 4.62AA |
| text.default on selection.bg | 14.38AAA | 10.14AAA | 13.12AAA | 9.88AAA |
| text.default on bg.zone | 13.06AAA | 14.04AAA | 14.02AAA | 13.87AAA |
| text.muted on bg.zone | 4.63AA | 6.40AA | 4.89AA | 6.36AA |
| text.link on bg.zone | 7.03AAA | 9.59AAA | 4.81AA | 9.61AAA |
Buttons and controls
14 pairs, all pass14 pairs, all pass14 pairs, all pass14 pairs, all pass14 pairs, all pass in all 4
| Pair | Bridge light | Bridge dark | Ocean light | Ocean dark |
|---|---|---|---|---|
| control.track on surface.default | 3.50AA | 4.70AA | 3.49AA | 4.30AA |
| control.checked.bg on surface.default | 8.87AA | 10.49AA | 5.15AA | 9.69AA |
| control.checked.fg on control.checked.bg | 8.87AAA | 11.43AAA | 5.15AA | 11.51AAA |
| control.thumb on control.track | 3.50AA | 3.26AA | 3.49AA | 3.24AA |
| action.primary.text on action.primary.bg | 8.87AAA | 11.43AAA | 5.15AA | 11.51AAA |
| action.primary.text on action.primary.bg-hover | 10.89AAA | 14.23AAA | 7.38AAA | 13.92AAA |
| action.primary.bg on surface.default | 8.87AA | 10.49AA | 5.15AA | 9.69AA |
| action.secondary.text on action.secondary.bg | 16.49AAA | 15.35AAA | 15.03AAA | 13.99AAA |
| action.secondary.text on action.secondary.bg-hover | 14.31AAA | 10.13AAA | 13.11AAA | 10.08AAA |
| action.ghost.text on surface.default | 10.88AAA | 14.31AAA | 10.83AAA | 13.11AAA |
| action.ghost.text on action.ghost.bg-hover | 9.45AAA | 9.45AAA | 9.45AAA | 9.45AAA |
| action.danger.text on action.danger.bg | 5.90AA | 5.90AA | 5.90AA | 5.90AA |
| action.danger.text on action.danger.bg-hover | 8.33AAA | 8.33AAA | 8.33AAA | 8.33AAA |
| action.primary.bg on bg.zone | 7.03AA | 9.59AA | 4.81AA | 9.61AA |
UI and borders
6 pairs, all pass6 pairs, all pass6 pairs, all pass6 pairs, all pass6 pairs, all pass in all 4
| Pair | Bridge light | Bridge dark | Ocean light | Ocean dark |
|---|---|---|---|---|
| border.strong on surface.default | 3.50AA | 4.70AA | 3.49AA | 4.30AA |
| border.strong on bg.default | 3.50AA | 5.11AA | 3.24AA | 5.14AA |
| border.strong on surface.raised | 3.50AA | 3.10AA | 3.49AA | 3.10AA |
| signal.default on surface.default | 5.27AA | 7.06AA | 5.15AA | 6.57AA |
| signal.default on bg.default | 5.27AA | 7.68AA | 4.79AA | 7.85AA |
| signal.default on bg.muted | 4.28AA | 4.66AA | 3.97AA | 4.74AA |
Focus
4 pairs, all pass4 pairs, all pass4 pairs, all pass4 pairs, all pass4 pairs, all pass in all 4
| Pair | Bridge light | Bridge dark | Ocean light | Ocean dark |
|---|---|---|---|---|
| focus.ring.color on surface.default | 8.87AA | 7.06AA | 5.15AA | 6.57AA |
| focus.ring.color on bg.default | 8.87AA | 7.68AA | 4.79AA | 7.85AA |
| focus.ring.color on surface.raised | 8.87AA | 4.66AA | 5.15AA | 4.74AA |
| focus.ring.color on bg.zone | 7.03AA | 6.46AA | 4.81AA | 6.52AA |
Feedback and status
18 pairs, all pass18 pairs, all pass18 pairs, all pass18 pairs, all pass18 pairs, all pass in all 4
| Pair | Bridge light | Bridge dark | Ocean light | Ocean dark |
|---|---|---|---|---|
| feedback.success.text on feedback.success.bg | 6.83AA | 11.51AAA | 6.83AA | 11.51AAA |
| feedback.warning.text on feedback.warning.bg | 7.22AAA | 12.41AAA | 7.22AAA | 12.41AAA |
| feedback.danger.text on feedback.danger.bg | 7.74AAA | 11.17AAA | 7.74AAA | 11.17AAA |
| feedback.info.text on feedback.info.bg | 7.51AAA | 11.23AAA | 7.51AAA | 11.23AAA |
| feedback.success.text on surface.default | 7.30AAA | 10.73AAA | 7.30AAA | 9.78AAA |
| feedback.warning.text on surface.default | 7.74AAA | 11.38AAA | 7.74AAA | 10.37AAA |
| feedback.danger.text on surface.default | 8.33AAA | 10.09AAA | 8.33AAA | 9.20AAA |
| feedback.info.text on surface.default | 8.07AAA | 10.17AAA | 8.07AAA | 9.27AAA |
| feedback.success.icon on feedback.success.bg | 4.68AA | 7.88AA | 4.68AA | 7.88AA |
| feedback.warning.icon on feedback.warning.bg | 5.02AA | 9.31AA | 5.02AA | 9.31AA |
| feedback.danger.icon on feedback.danger.bg | 5.48AA | 7.21AA | 5.48AA | 7.21AA |
| feedback.danger.icon on surface.default | 5.90AA | 6.51AA | 5.90AA | 5.94AA |
| feedback.info.icon on feedback.info.bg | 5.22AA | 7.46AA | 5.22AA | 7.46AA |
| text.on-solid on feedback.success.solid | 5.00AA | 5.00AA | 5.00AA | 5.00AA |
| text.on-solid on feedback.warning.solid | 5.38AA | 5.38AA | 5.38AA | 5.38AA |
| text.on-solid on feedback.danger.solid | 5.90AA | 5.90AA | 5.90AA | 5.90AA |
| text.on-solid on feedback.info.solid | 5.62AA | 5.62AA | 5.62AA | 5.62AA |
| text.on-solid on surface.strong | 8.87AAA | 8.87AAA | 7.38AAA | 7.38AAA |
Charts
14 pairs, all pass14 pairs, all pass14 pairs, all pass14 pairs, all pass14 pairs, all pass in all 4
| Pair | Bridge light | Bridge dark | Ocean light | Ocean dark |
|---|---|---|---|---|
| chart.series.1 on surface.default | 3.48AA | 7.06AA | 3.41AA | 6.57AA |
| chart.series.1 on bg.default | 3.48AA | 7.68AA | 3.17AA | 7.85AA |
| chart.series.2 on surface.default | 5.62AA | 6.75AA | 5.62AA | 6.16AA |
| chart.series.2 on bg.default | 5.62AA | 7.34AA | 5.23AA | 7.35AA |
| chart.series.3 on surface.default | 5.00AA | 7.34AA | 5.00AA | 6.69AA |
| chart.series.3 on bg.default | 5.00AA | 7.98AA | 4.66AA | 7.99AA |
| chart.series.4 on surface.default | 5.38AA | 8.54AA | 5.38AA | 7.79AA |
| chart.series.4 on bg.default | 5.38AA | 9.28AA | 5.01AA | 9.29AA |
| chart.series.5 on surface.default | 5.73AA | 6.60AA | 5.73AA | 6.02AA |
| chart.series.5 on bg.default | 5.73AA | 7.17AA | 5.33AA | 7.18AA |
| chart.series.6 on surface.default | 3.50AA | 6.99AA | 3.49AA | 6.42AA |
| chart.series.6 on bg.default | 3.50AA | 7.60AA | 3.24AA | 7.66AA |
| chart.axis on surface.default | 5.85AA | 6.99AA | 5.24AA | 6.42AA |
| chart.axis on bg.default | 5.85AA | 7.60AAA | 4.88AA | 7.66AAA |
What every component guarantees
- Keyboard and screen readers. Every interactive component is keyboard operable, with the right role, name and state. Behavior comes from native elements or Base UI parts.
- Visible focus. A 2px ring in the focus color, offset by 2px, on
:focus-visibleonly. Inputs draw it inside the field. - Color is never the only signal. Status has text and an icon; an invalid field has a message.
- Targets of at least 24 by 24 px in both densities.
- Reduced motion. With
prefers-reduced-motion: reduce, every motion duration drops to 0. - Checked in CI. Storybook runs the accessibility addon in error mode, and component tests run axe-core.
How we check
Thresholds
Bridge targets WCAG 2.2 AA. Text needs 4.5:1 against its background, and reaches AAA at 7:1. Control edges, icons and focus rings need 3:1 (WCAG 1.4.11), which has no AAA level. Ratios are rounded down, so 4.496 never shows as a passing 4.50.
Text or UI
Each pair carries its own minimum. A pair gated at 4.5:1 is text: body copy, labels, links, button text, chart axis labels. A pair gated at 3:1 is a UI part: borders, control tracks, icons, focus rings, chart series. Text samples show "Aa"; UI samples show a stroke.
The build gate
The pairs live in packages/tokens/src/contrast.checks.json. The token build resolves each one in every brand and theme and fails below its minimum, so a token change that breaks a pair never reaches the library. To gate a new combination, add ["<fg token>", "<bg token>", <min>] to that file.
When a pair fails
- Fix it with a token change, never locally in a screen or a component. A local fix hides the problem and the next team hits it again.
- Open an issue, or start an exploration in Studio and send it for review, with the pair, the ratio and where it shows up. A new token value needs the design owner's approval, then ships once the automatic checks pass.
- Until the fix is in the library, avoid that pair in new places.