Bhinish Dhiman· updated 5 October 2026
How to generate a colour palette you can actually set text in
Lock the colour you must keep, press space to re-roll the rest, and turn on Audit. Each column names its strongest partner inside the palette and the ratio between them, and offers a fix at the same hue when no partner reaches 4.5:1. Checking each colour against white or black proves nothing, because every colour clears 4.5:1 against one of the two.
A generated palette nearly always looks right as a row of swatches. The trouble starts when you set a heading in one of the colours, put it on another, and find the pair you liked has almost no contrast between them. This guide covers how to use the palette generator so the set you keep contains a colour you can set text in, on the background you are actually shipping.
Every colour passes on white or on black
Start with the fact that reframes the job. A colour’s contrast ratio against white, multiplied by its ratio against black, is always 21. The WCAG formula gives 1.05 ÷ (L + 0.05) against white and (L + 0.05) ÷ 0.05 against black, where L is the colour’s relative luminance, and the L terms cancel: 1.05 ÷ 0.05 = 21. So the worst case for a colour’s better ratio is √21, about 4.58, and every colour there is clears 4.5:1 against one of the two.
A text colour, then, is not a property of a colour on its own. It is a colour that clears 4.5:1 against the particular background it will sit on. “Can this carry text?” has no answer until you say on what.
That is why the tool’s audit does not ask about white and black. It used to: its count of colours that could “carry body text on white or black” read every colour as usable on every palette ever generated, and its fix button could never appear. Writing this guide is how we noticed. It now asks what a palette is actually for: can this colour carry text on another colour in the same set?
Generating the palette, step by step
- Put in the colour you have to keep. Each column’s hex code is an editable field: click it and type or paste a value. Then press the padlock at the top right of that column to lock it.
- Press the spacebar, or Generate. Every column without a lock is re-rolled and locked ones stay. If you lose a set you wanted, Undo (or the Z key) goes back one step, and only one.
- Set the number of columns. Add and Remove take the palette anywhere from two to eight colours.
- Read the foot of each column. It names that column’s strongest partner in the palette, with the ratio between them. “Carries text in this palette” means a partner reaches 4.5:1; otherwise a fix → link offers the nearest colour at the same hue that would, measured against the palette’s own darkest or lightest colour. The Audit button shows and hides these lines; they are on when the page opens.
- Lock what you are keeping and re-roll the rest. Lock all (the L key) holds every column at once; pressing it again frees them all.
- Keep it. Share copies a link that reopens exactly this palette, Save here keeps it in your recent activity on this device, and Export copies it as CSS, OKLCH, Tailwind v4, SCSS, JSON, Figma tokens or SVG swatches.
How a re-roll places the free colours
Locking does more than leave a column alone. The leftmost locked colour becomes the anchor, and its hue and chroma decide where everything else goes. The free columns are stepped through hue from 60° below the anchor’s hue towards 60° above it, each nudged by up to 12° either way at random. Their chroma is set between 45% and 125% of the anchor’s, with the anchor treated as having at least 0.06.
Lightness is walked left to right across the free columns, starting at an OKLCH lightness of 0.22 and climbing in equal steps that share out 0.62 between them. With one column locked and four free, the free ones are aimed at 0.22, 0.375, 0.53 and 0.685, each moved by up to 0.04.
Two practical consequences follow from that arithmetic.
- The leftmost free column is always the darkest. It is aimed at 0.22, which makes it the likeliest text colour on a light page.
- A re-roll never produces a pale surface colour. Even at eight columns with one locked, the lightest free column is aimed at 0.22 + 0.62 × 6/7, about 0.75. If you want a near-white page or card colour in the set, type it into a column and lock it. The palette the tool opens with does exactly that: its fifth colour, #f4f1ea, is typed in, not generated.
The opening palette, against itself
The tool opens with #0f172a, #1e5aa8, #3ba0c9, #e8b04b and #f4f1ea. The on-white column is there for comparison only; the tool no longer shows it. The partner column is what each column’s foot reads, rounded down to two decimal places as the tool rounds.
| Colour | On white (for comparison) | Strongest partner in the palette |
|---|---|---|
| #0f172a | 17.85:1 | #f4f1ea, 15.82:1 |
| #1e5aa8 | 6.81:1 | #f4f1ea, 6.03:1 |
| #3ba0c9 | 2.97:1 | #0f172a, 5.99:1 |
| #e8b04b | 1.95:1 | #0f172a, 9.13:1 |
| #f4f1ea | 1.12:1 | #0f172a, 15.82:1 |
The strip reads 5 of 5 here, and this time it means it: every colour has a partner it can carry text on, because the opening set was built with a dark end and a light end. On white alone, only two of the five would pass.
A popular mid-tone palette shows what failing looks like. #264653, #2a9d8f, #e9c46a, #f4a261 and #e76f51, the teal, sand and coral set, scores 3 of 5. The mid teal’s best partner is the dark teal at 3.03:1, and its fix is #53bfb0, which reaches 4.53:1 against #264653 with the hue held at 183°. The coral tops out at 3.25:1. Neither colour is wrong; the set simply has nothing light enough to pair them with.
The amber is the instructive one. At 1.95:1 it is useless as text on white, yet amber on the navy measures 9.13:1. Whether a colour is a text colour depends entirely on what sits behind it.
The check the strip does make
The strip’s second sentence is a palette-level test that a contrast checker never runs, because it compares one foreground with another. It simulates every pair of colours under eight types of colour-vision deficiency, using the Machado, Oliveira and Fernandes (2009) model, and names any pair whose CIEDE2000 distance falls below 11 under any of them. Two colours can each clear 4.5:1 against the page and still be hard to tell apart for someone with deuteranomaly, which the tool’s notes put at roughly 5% of men.
If the strip names a pair, the colour blindness simulator shows it under each vision type, and How to build a colour-blind safe palette covers the fix.
Other ways to do it
There is no built-in method on macOS, Windows or iPhone for generating a palette and auditing it, and no command-line route among those these guides vouch for. The manual alternative is any generator followed by a contrast checker, one pair at a time, for every pair you mean to set text in.
| This tool | A typical spacebar generator | |
|---|---|---|
| Locking | The locked hue anchors where the others go | Locked slot skipped, the rest random |
| Contrast per colour | Its strongest partner in the palette, with the ratio | None, or against white only |
| Palette-level check | Pairs that collapse under colour-vision simulation, named | Not offered |
| Saving | Colours carried in the link | An account |
Checking that nothing leaves the tab
There is no file to upload here, and the palette lives in the address bar after the # sign. Browsers do not send that part of a URL to the server, so a shared link opens without the colours ever reaching the site. To confirm it, open DevTools, go to the Network panel and press the spacebar a few times: nothing that goes out carries your colours.
Open the palette generator, lock the colour you cannot change, and read each column’s partner before you settle on a set. For the thresholds themselves, What contrast ratio do you actually need? sets out which number applies where.