How to Pick a Color Palette
Choosing colours feels arbitrary until you have a method. Here is one that produces usable, accessible results every time, whether you are building a website, a slide deck, a chart, or an app.
1. Start with one colour
Pick a single colour that fits the mood — a brand colour you already have, a colour pulled from a photograph, or just one you like. Everything else will derive from it, so this is the only fully subjective decision you make. Note its HSL values (hue, saturation, lightness); working in HSL makes the next steps mechanical.
2. Apply a harmony rule
Colour harmonies are fixed geometric relationships on the colour wheel. Pick one based on how much contrast you want:
- Monochromatic — one hue at several lightness and saturation levels. Safe, calm, elegant; the hardest to make visually interesting, so lean on typography and spacing.
- Analogous — hues next to each other on the wheel (e.g. blue, blue-green, teal). Cohesive and low-tension. Good for backgrounds and large areas.
- Complementary — two hues opposite each other (blue and orange, purple and yellow). Maximum contrast and energy. Use the second hue sparingly, only for things that must jump out.
- Split-complementary — your hue plus the two neighbours of its opposite. Almost as punchy as complementary but easier to balance.
- Triadic — three hues evenly spaced (120° apart). Vivid and balanced, but harder to control; usually one dominates and the other two are accents.
The colour palette generator applies each of these from your base colour so you can compare them side by side.
3. Build a neutral ramp
Most of any interface is neutral — backgrounds, borders, body text, muted labels. Do not use pure grey. Instead, take your base hue and desaturate it hard (down to 3–8% saturation) at a range of lightness values: a near-white, two or three light greys, a mid grey, two or three dark greys, and a near-black. These “tinted neutrals” feel intentional and quietly reinforce your colour, where flat grey looks generic.
4. Assign roles, not just colours
A palette is only useful once every colour has a job. For a typical interface:
| Role | Typically |
|---|---|
| Surface / background | Your near-white (or near-black for dark mode) |
| Card / raised surface | A hair lighter or darker than the background |
| Border / divider | A light tinted neutral |
| Body text | A near-black tinted neutral — not #000000 |
| Muted text | A mid tinted neutral, still passing contrast |
| Primary action | Your base hue (adjusted for contrast — see step 5) — main buttons, links |
| Accent | One additional harmony colour — highlights, badges, secondary emphasis |
| Semantic | Green (success), amber (warning), red (error) — kept consistent |
Three to five decorative colours is plenty. The neutrals do the heavy lifting.
5. Check contrast — the step everyone skips
Accessibility standards (WCAG 2.1 AA) require:
- Body text: contrast ratio of at least 4.5:1 against its background.
- Large text (≈24px, or 19px bold) and UI components / graphics: at least 3:1.
A vivid mid-tone hue almost never passes as text on white — you will need a noticeably darker variant for links and button labels, while keeping the bright version for large fills. Run every text/background pair and every button-colour/label pair through a contrast checker and adjust the lightness until it passes. Do this for dark mode separately if you have one.
Working in a colour space that helps you
Pick colours in HSL or OKLCH, not hex or RGB. In HSL you can hold the hue and saturation steady and change only the lightness to build a ramp, which is exactly what a neutral ramp and a set of button states need. OKLCH (now supported in CSS) goes further: it is perceptually uniform, so a lightness step of 0.1 looks like the same jump whether the hue is yellow or blue. HSL’s weakness is that yellows look much lighter than blues at the same L value, which is why hand-built HSL ramps often need eyeball corrections.
Practical approach: define your palette as CSS custom properties, one per role, and derive hover/active/disabled states by nudging lightness (and slightly reducing chroma for disabled).
A worked mini-palette
Base hue: a blue at roughly hsl(215, 90%, 50%).
| Token | Value (approx.) | Role |
|---|---|---|
--surface |
hsl(215, 20%, 99%) |
Page background |
--card |
hsl(215, 20%, 100%) |
Raised surface |
--border |
hsl(215, 15%, 88%) |
Dividers |
--text |
hsl(215, 25%, 15%) |
Body text (≈14:1 on surface) |
--muted |
hsl(215, 12%, 45%) |
Secondary text (≈5:1, passes) |
--primary |
hsl(215, 80%, 42%) |
Buttons, links (darkened from the base for 4.5:1 on white) |
--primary-hover |
hsl(215, 80%, 36%) |
Hover |
--accent |
hsl(150, 65%, 38%) |
One harmony colour — success / highlight |
Every text and button colour here has been pulled toward a lightness that passes contrast; the bright base blue lives only in large fills and focus rings.
Dark mode from the same palette
Do not just invert. Build a parallel set of tokens where the surface is a very
dark, slightly hue-tinted grey (not #000), text is an off-white, borders are a
lighter grey than the surface, and the primary colour is usually made
lighter and slightly less saturated so it has enough contrast against the dark
background. Test the dark set against contrast targets separately — a colour that
passes on white often fails on dark and vice versa.
Common mistakes
- Too many hues. Two or three decorative colours, plus neutrals and semantics, is enough for almost anything.
- Pure black on pure white.
#000on#FFFis harsh; soften both slightly. - Relying on colour alone to convey meaning. Red/green status is invisible to many colour-blind users — pair it with an icon, a label, or a shape.
- Choosing colours as swatches, not in context. A colour shifts depending on what surrounds it and how much area it covers. A swatch that looks great small can overwhelm as a full-page background — mock up a real screen before committing.
- Skipping the disabled and hover states. Each interactive colour needs those variants; derive them by nudging lightness.
The bottom line
Start from one colour, pick a harmony rule for the amount of contrast you want, build a ramp of hue-tinted neutrals, give every colour an explicit role, then verify every text and UI pair against 4.5:1 (or 3:1 for large text). Keep it to three or so decorative colours and never lean on colour alone for meaning. Generate and compare harmonies from your base colour with the colour palette generator.