UI colour scheme builder — a light or dark theme from one primary colour

Enter one primary colour, choose light or dark, and get 14 named interface colours as CSS custom properties, with text colours that meet WCAG contrast and a live preview.

Live demo · real result from this tool
Theme

Press Generate to create a result.

Processed on your device — nothing is uploaded.

How to use the UI colour scheme builder

  1. Pick the Primary colour, usually your brand or main action colour.
  2. Choose the Theme: Light or Dark.
  3. Pick where the secondary comes from under Secondary from.
  4. Set a Variable prefix if you do not want the default color.
  5. Copy the CSS custom properties or save them as color-scheme.css, and review the contrast table and preview.

What it does and when to use it

Most interfaces need more than a brand colour: a page background, card surfaces, borders, body text, quieter helper text, and colours for success, warning, danger and info. Choosing those by eye takes time and often fails contrast checks. This builder derives the whole set from one colour, gives the neutrals a faint tint of your primary so they feel related, and checks the important pairs.

It is a solid first draft for a prototype, an admin panel or a side project’s dark mode. Fine-tune the result afterwards: test any pair in the contrast checker, add steps with the tints and shades generator, or compare more secondary options in colour harmonies.

How it works

Everything is built in OKLCH, where lightness matches what the eye sees. The neutrals use the primary’s hue with very low chroma. In light mode the background is OKLCH lightness 0.985 and the surface is white; in dark mode they are 0.17 and 0.21.

Text, muted text, primary, secondary and the status colours are then checked against the background with the WCAG 2.x contrast formula. Any that fall short have their lightness moved until they pass, using the same search as the contrast checker’s suggestions. The hover colour is the adjusted primary 8 OKLCH lightness points darker in light mode, or lighter in dark mode. The status colours use fixed hues: success 150°, warning 70°, danger 27°, info 245°.

Worked examples

These are the builder’s own results.

Indigo #4f46e5, light. The primary is kept as #4f46e5, with on-primary #ffffff (6.29:1), background #f9fafe and text #181a24 (16.61:1). The analogous secondary is #0069bf.

The same indigo, dark, prefix “brand”. –brand-background is #0e0f16, text #eceef5 (16.49:1) and muted text #a1a4b1 (7.70:1). The primary stays #4f46e5, which reaches only 3.04:1 on the dark background, so use it for buttons rather than small text.

Yellow #facc15, light. Yellow is too pale for a white page, so the primary becomes #b38c00 (3.02:1), and the on-primary switches to the dark #121726.

Limits and tips

  • The status colours ignore your brand hue; adjust them if your brand is itself red or green.
  • One primary in, one theme out. Run it twice for matching light and dark sets.
  • All colours are made and checked in your browser.

Frequently asked questions

Why did my primary colour change?
The builder needs the primary to reach at least 3:1 contrast against the background, so buttons and links stay visible. If yours does not, it moves the OKLCH lightness just far enough, keeping hue and chroma. Yellow
Which contrast levels does it aim for?
Text reaches at least 7:1 on the background, muted text at least 4.5:1, and primary, secondary and the four status colours at least 3:1. The on-primary colour is white or a near-black, whichever contrasts more with the primary.
Are the status colours safe for small text?
Not always. They are only guaranteed 3:1, which suits icons, borders and large text. The contrast table shows the real ratio; in the light indigo example, danger reaches 4.46:1, just under the 4.5:1 needed for body text.
How is the secondary colour chosen?
It is the primary rotated on the OKLCH hue wheel by the harmony you pick under Secondary from. Complementary turns 180°, Analogous −30°, Triadic 120° and Split-complementary 150°.
Can I change the variable names?
Yes. Set Variable prefix and every name changes, for example brand gives --brand-primary. The prefix is lower-cased, and spaces or symbols become hyphens.

Written by the ToolsRift team · Last updated

Pages are drafted with AI assistance and checked by automated tests. How we write and check pages.

Was this tool useful?

Report a problem

Start typing to search every tool.

↑ ↓ to moveEnter to openEsc to close