Check every color in a palette against every other in one table. Paste up to twelve colors and get the full WCAG contrast matrix with pass/fail marking at your chosen threshold — the fastest way to find which pairs in a design system can safely carry text.
Generated locally in your browser — your colors, settings and code never leave this page.
Auditing pairs, not colors
Accessibility lives in pairs. No color passes or fails alone — readability is a relationship between a foreground and its background — so auditing a palette means auditing its pair space, which grows quadratically: five colors make ten unique pairs, ten make forty-five. Checking them one at a time in a two-color checker is where audit discipline goes to die. The matrix computes the entire pair space at once, colors the verdicts, and turns an afternoon of clicking into a glance.
Reading technique
The matrix is symmetric (WCAG contrast has no direction), so read either triangle. Scan patterns, not cells: a row that is red across the board is a mid-toned color that can text-pair with nothing — the palette’s dead zone; a column of greens under your lightest color is your text-candidate list. The pass count in the summary is the palette’s one-number health score at that threshold, comparable across candidate palettes.
The three-threshold audit
One matrix per threshold answers a different question. At 4.5:1: which pairs can carry normal text — the binding constraint. At 3:1: which additionally serve large text, icons and component boundaries (the 1.4.11 world). At 7:1: the AAA subset for long-form reading. Running all three takes seconds and yields a complete pairing policy; the CSV export turns it into the spreadsheet your design system documentation was missing.
Fixing a sparse matrix
Few greens means the palette clusters in lightness — the cure is structural, not chromatic: pull some colors lighter and push others darker (Shades & Tints per color) until the lightness spread supports pairing, then re-run. Hue changes rarely move contrast; lightness changes always do. Iterating palette → matrix → adjustment converges in two or three rounds, and the Accessible Palette Generator short-circuits the loop when contrast is the primary requirement from the start.
Matrix results as design-system law
The step that makes an audit stick: convert the passing cells into named, documented pairings — “ink-on-paper”, “ink-on-surface”, “inverse-on-primary” — and declare undocumented combinations off-limits in component code. Design systems that encode this (lint rules against raw color pairs, components accepting only pairing tokens) stop regressing between audits, because the matrix’s knowledge lives in the codebase instead of in a spreadsheet someone ran last quarter. The CSV export is the seed of exactly that artifact.
How to use the Palette Contrast Matrix
- Paste your palette – up to twelve colors, any notation.
- Pick the threshold: 3:1, 4.5:1 or 7:1.
- Read the matrix: green cells pass, red fail, headers show the colors.
- Export as CSV or a pass/fail report.
Frequently asked questions
How do I read the contrast matrix?
Rows and columns are your palette in order; each cell is the WCAG ratio between that pair, colored by pass/fail at your threshold. The matrix is symmetric (contrast has no direction), so scan either triangle. The summary counts how many pairs are usable.
Which threshold should I set for a design-system audit?
Audit at 4.5:1 first – that is normal-text AA and the binding constraint for most UI. Rerun at 3:1 to find the additional pairs valid for large text and non-text components, and at 7:1 if AAA body text is in scope. Three runs, three layers of the pairing map.
What does it mean if a palette has very few passing pairs?
That its colors cluster in lightness – the usual outcome of picking pretty colors without a lightness plan. The fix is not new hues but restructured lightness: stretch some colors light and some dark (Shades and Tints does this per color) and re-run.
Can I paste design tokens straight from code?
Yes – the parser takes hex, rgb(), hsl(), oklch() and named colors, comma or newline separated, so a grep of your tokens file drops straight in. Values are echoed in the CSV export for tracing back.
Why cap the matrix at twelve colors?
A 12×12 grid is 66 unique pairs – already at the edge of reviewable. Past that, matrices stop being read and start being scrolled. Audit in role groups (text colors × surface colors) rather than everything × everything.
Does a passing cell mean the pair is good design?
It means the pair is readable – necessary, not sufficient. Aesthetics, hierarchy and color-vision distinctness are separate questions; the matrix clears the legal floor so taste can operate above it.
How do I document the results for my team?
The CSV export drops into a spreadsheet as the canonical pairing table, and the pass/fail text report pastes into PRs and audits. Pair it with rules ("text only on passing pairs at 4.5") and the matrix becomes policy, not advice.