Contrast & Accessibility
Every ratio on this page is computed live from the token metadata, per mode, with the same functions the library ships. If your theme overrides the palette, you can run the identical WCAG check on it.
Requirements
WCAG 2.2 grades text contrast by ratio and text size: large text is at least 24px, or 18.66px bold. Section 508 incorporates WCAG 2.0 AA, so an AA pass at a given size is also a 508 pass.
| Level | Normal text | Large text |
|---|---|---|
| WCAG AA | 4.5:1 | 3:1 |
| WCAG AAA | 7:1 | 4.5:1 |
| Section 508 | 4.5:1 | 3:1 |
Pairing checker
Pick any two colors (palette hues, intent roles in either mode, or resolved text and surface roles) and read the ratio and pass/fail grades live.
Normal text: a birdie putt from the circle's edge. (16px)
Large text: par saves win rounds. (24px)
Contrast ratio 5.17:1 · relative luminance 0.153 on 1.000
| Requirement | Minimum | Result |
|---|---|---|
| WCAG AA — normal text | 4.5:1 | Pass |
| WCAG AAA — normal text | 7:1 | Fail |
| WCAG AA — large text | 3:1 | Pass |
| WCAG AAA — large text | 4.5:1 | Pass |
| Section 508 — normal text | 4.5:1 | Pass |
| Section 508 — large text | 3:1 | Pass |
How to read the ratio and grades:
- Relative luminance
- Perceived brightness on a 0 (black) to 1 (white) scale. The contrast ratio is computed from these two values.
- Pass Fail
- In the table above, each row is graded on its own: Pass meets that requirement's minimum ratio, Fail does not. A pairing can pass AA and still fail the stricter AAA on the next row.
- AAA AA AA Large
- In the sections below, a badge names the highest grade a pairing reaches, one per text size (16px and 24px): AAA (at least 7:1 normal, 4.5:1 large), AA (4.5:1 normal, 3:1 large), or AA Large (clears 3:1, large text only). A ratio under 3:1 reaches no grade and shows a red Fail.
Text on surfaces
Every token the theme paints text with (the semantic text roles and all seven intents) on both
surface roles, in both modes, at normal (16px) and large (24px) sizes. Each panel uses the
values that mode actually resolves: the default palette on light surfaces, the dark theme's
companions ([data-theme="dark"]) on dark ones.
Rendered on surface · light (#ffffff) with the light-mode
token values.
Rendered on surface-muted · light (#f6f7f7) with the light-mode
token values.
Rendered on surface · dark (#000000) with the dark-mode
token values.
Rendered on surface-muted · dark (#27292c) with the dark-mode
token values.
| Token (light / dark) | surface · light | surface-muted · light | surface · dark | surface-muted · dark |
|---|---|---|---|---|
text #000000 · #ffffff | 21.00 AAA | 19.57 AAA | 21.00 AAA | 14.59 AAA |
text-muted #6b7280 · #9ca3af | 4.83 AA | 4.50 AA | 8.27 AAA | 5.74 AA |
intent-neutral #6b7280 · #9ca3af | 4.83 AA | 4.50 AA | 8.27 AAA | 5.74 AA |
intent-primary #2563eb · #60a5fa | 5.17 AA | 4.82 AA | 8.26 AAA | 5.74 AA |
intent-secondary #7c3aed · #a78bfa | 5.70 AA | 5.31 AA | 7.72 AAA | 5.36 AA |
intent-danger #b91c1c · #f87171 | 6.47 AA | 6.03 AA | 7.59 AAA | 5.27 AA |
intent-warning #b45309 · #fbbf24 | 5.02 AA | 4.68 AA | 12.58 AAA | 8.74 AAA |
intent-success #15803d · #4ade80 | 5.02 AA | 4.67 AA | 12.05 AAA | 8.37 AAA |
intent-info #0e7490 · #22d3ee | 5.36 AA | 4.99 AA | 11.62 AAA | 8.07 AAA |
Solid intent backgrounds
The solid Button and Badge case. The reference theme paints solid
text with --hz-color-surface (white by default, black under the dark theme) because the dark
companions are lighter than the surfaces they sit on.
Soft intent surfaces (Alert & Badge)
The reference theme derives these surfaces with color-mix(): backgrounds mix
10–14% of the intent color into the
surface in light mode and 22–28% in dark
(weak tints barely read as color on a dark surface). Text mixes
65–70% toward the text role in both modes.
Tune the background strength with the --hz-alert-tint and --hz-badge-tint hooks. Everything below is that
derivation over the mode's resolved values: proof the tints hold contrast, not only the raw
hues.
Check your own palette
The math behind this page is part of the library: hexToRgb, rgbToHex, mixSrgb, relativeLuminance, contrastRatio, gradeContrast, bestLevel, and bestLevelLarge, exported from the package root and @hyzer-labs/ui/utils. Pure functions over hex strings (no DOM, SSR-safe), with
the token metadata importable from @hyzer-labs/ui/tokens. If your theme overrides
the palette, assert your pairings in a unit test the same way this library does:
import { gradeContrast, contrastRatio, mixSrgb } from '@hyzer-labs/ui';
import { palette } from '@hyzer-labs/ui/tokens';
// Your override for --hz-palette-primary
const brand = '#0f766e';
gradeContrast(brand, palette.white).aaNormal; // text on surface
gradeContrast(palette.white, brand).aaNormal; // solid button text
// On surface-muted: the same 6% color-mix the theme derives
contrastRatio(brand, mixSrgb(palette.gray, palette.white, 0.06));For the full override workflow, see Theming → Tokens & Overrides: plain-CSS recipes and the hyzer CLI, whose generate step runs this same report over your config.
References: WCAG 2.2: 1.4.3 Contrast (Minimum) · WCAG 2.2: 1.4.6 Contrast (Enhanced) · WCAG 2.2: 1.4.11 Non-text Contrast · WAI-ARIA 1.2 · ARIA APG · Section 508