Color contrast grid
A contrast grid checks every color in a palette against every other color at once and gives each pair its WCAG ratio and verdict. Every pair, with the number, free and without an account. Normal text needs 4.5:1, large text and interface graphics need 3:1. Checking pairs one at a time is how accessible-looking palettes ship with unreadable combinations.
Your palette
Rows are the text color. Columns are the background.
The first list becomes text colors only. Every row is checked against every background here.
22 pairs passing AA
- Normal text AA
- 22 of 56 (39%)
- Normal text AAA
- 12 of 56 (21%)
- Large text / UI AA
- 30 of 56 (54%)
- Large text AAA
- 22 of 56 (39%)
No color in this palette is graphics-only: each one can hold normal text against at least one partner.
| text \ background | ink | primary | accent | accent deep | muted | mist | paper | surface |
|---|---|---|---|---|---|---|---|---|
| ink | same | ink on primary | ink on accent | ink on accent deep | ink on muted | ink on mist | ink on paper | ink on surface |
| primary | primary on ink | same | primary on accent | primary on accent deep | primary on muted | primary on mist | primary on paper | primary on surface |
| accent | accent on ink | accent on primary | same | accent on accent deep | accent on muted | accent on mist | accent on paper | accent on surface |
| accent deep | accent deep on ink | accent deep on primary | accent deep on accent | same | accent deep on muted | accent deep on mist | accent deep on paper | accent deep on surface |
| muted | muted on ink | muted on primary | muted on accent | muted on accent deep | same | muted on mist | muted on paper | muted on surface |
| mist | mist on ink | mist on primary | mist on accent | mist on accent deep | mist on muted | same | mist on paper | mist on surface |
| paper | paper on ink | paper on primary | paper on accent | paper on accent deep | paper on muted | paper on mist | same | paper on surface |
| surface | surface on ink | surface on primary | surface on accent | surface on accent deep | surface on muted | surface on mist | surface on paper | same |
8 colors, 56 ordered pairs, 34 failing at 4.5:1 for normal text.
- Network requests
- ·
- Our own script
- ·
Was this tool useful?
Why one pair at a time is not enough
The two big contrast checkers take exactly two colors. That works when you've got two colors. A design system has eight or nine, and the interesting failures are never the pair you thought to check. They're the accent on the tile, the muted text on the card, the link color on the one surface you added last.
Here is a real one. Benchvale's own palette started with a brighter accent at
#23A6B8. It looked right. Against the primary tile it measured
2.82:1, under the 3:1 floor that graphics and interface elements
need, so the mark itself would have failed. Nothing would have told us without
checking that specific pair, and that pair is one of 72 in a nine color palette.
The fix was two colors instead of one:
a bright accent for marks and a deeper #0E6B78 for anything that
carries text.
That is the mistake this grid is built to catch, and it is the most common palette mistake there is: a color that passes as a graphic and fails as text. When a color in the paste can hit 3:1 against some partner and never 4.5:1 against any, its name is listed in the summary above the grid, so the graphics-only set is a list of colors rather than only a mode switch.
How to read the grid
Rows are the text color. Columns are the background. Each cell gives the ratio and the verdict.
- AAA is 7:1 or better for normal text, 4.5:1 for large text. Graphics have no AAA.
- AA is 4.5:1 for normal text, 3:1 for large text and interface graphics.
- Fail means don't use that pair for that purpose. It may still be fine for a decorative shape that carries no meaning.
Large text means 18.66px bold or 24px regular and above. Icons, borders, focus rings and chart strokes count as graphics and use the 3:1 floor.
What the ratio does not tell you
Contrast ratio is a luminance calculation. It says nothing about hue, so two colors can pass at 5:1 and still be indistinguishable to someone with deuteranopia. Run the palette through the color blindness simulator as well, and never let color be the only thing carrying meaning.
Questions
How do I check every color pair in a palette?
Paste your colors, one per line, as hex with an optional name after each. Rows are the text color and columns are the background, so every cell shows one pair's WCAG ratio and verdict. The default 8-color palette makes 56 ordered pairs. At 4.5:1 for normal text, 34 of them fail. The counts above the grid update as you type.
Can I use it to check chart colors?
Yes. Pick "Large text or graphics." Chart lines and bars that carry data are graphical objects under WCAG 2.2 success criterion 1.4.11, which asks for 3:1 against adjacent colors. Turn on "Use a separate background list" to test your series against the chart background alone. On white, warning yellow #F9AB00 scores 1.93:1 and fails, while info blue #1A73E8 passes at 4.51:1. Contrast can't tell you whether two series look alike to a color blind reader, so run them through the color blindness simulator too.
Why does my brand accent fail?
The ratio measures luminance only, so a bright, saturated color can still sit too close to a light background. Benchvale's own accent, #2FBFD0, scores 2.06:1 on #F5F7F9. That misses even the 3:1 floor for graphics. Our fix was a second, deeper shade for text: #0E6B78 scores 5.76:1 on the same background. Accent colors that fail as text walks through it.
How do I get the results out?
Copy results as text gives one line per pair, like ink on paper 16.32:1 AAA. Copy as CSS variables gives a :root block with one custom property per color, such as --ink:#131A22;. Copy share link copies a link that carries the palette after the #. For SCSS, JSON tokens or contrast notes inside the file, use palette to CSS.
Why does it stop at 14 colors?
Fourteen colors already make 182 ordered pairs, and a bigger grid gets hard to read. Colors past the 14th in each list are left out. The page tells you above the grid and in the status line how many were left out.
Does this send my colors anywhere?
No. Every ratio is calculated in this tab. Before any update to this page goes live, an automated check types into every box and presses every button, and blocks the update if what it typed turns up in a request. A share link carries your palette after the # in the address. Browsers don't send that part to a server.
Related tools
Once the palette survives the grid: the contrast checker is the same math for one pair when you already know which two colors to test. Export it to CSS variables and JSON tokens, which carries the contrast verdicts into the file as comments. Contrast is only half the check, so run it through the color blindness simulator as well: two colors can pass at 5:1 and still be the same gray to a large number of people. How to read a contrast ratio explains what the number itself means. And accent colors that fail as text is the specific failure this grid was built to catch, with our own numbers.