Tailwind colours

A scale previewed on real components, with every contrast measured.

LightDark

Examples · light

Buttons

PrimarySecondaryOutlineDisabled

5.68:1 · primary label · 4.5:1 needed

9.23:1 · secondary label · 4.5:1 needed

Badges

DefaultSubtleOutline

6.65:1 · subtle badge, 11px · 4.5:1 needed

Input

you@example.com
Focused

1.86:1 · input border · 3:1 for control boundaries

Alert

Heads up

A tinted surface is where most scales lose their body text.

7.37:1 · alert body text · 4.5:1 needed

Table

NamePlanValue
AcmePro$4,200
GlobexTeam$1,100

5.23:1 · table header · 4.5:1 needed

Chart

$213,000

5.68:1 · series on surface · 3:1 for meaningful graphics

v4 emits OKLCH, because that is what Tailwind v4's own palette uses — and it keeps the ramp perceptually even if you edit it later.

@theme {
  --color-brand-50: oklch(97.2% 0.013 262.4);
  --color-brand-100: oklch(93.8% 0.030 262.5);
  --color-brand-200: oklch(87.8% 0.060 261.0);
  --color-brand-300: oklch(80.1% 0.100 260.6);
  --color-brand-400: oklch(70.2% 0.156 260.9);
  --color-brand-500: oklch(60.7% 0.213 260.9);
  --color-brand-600: oklch(52.4% 0.224 260.8);
  --color-brand-700: oklch(44.3% 0.189 260.8);
  --color-brand-800: oklch(36.3% 0.155 260.8);
  --color-brand-900: oklch(28.6% 0.120 260.9);
  --color-brand-950: oklch(21.3% 0.087 260.9);
}

What Tailwind colour scale is

An eleven-step scale registered under one name so utilities such as bg-brand-500 and text-brand-700 exist. In Tailwind v4 the scale is declared in CSS inside an @theme block rather than in a JavaScript config, and the framework’s own default palette is expressed in OKLCH.

What this tool does that others do not

  • v4 @theme output by default

    v4 moved configuration into CSS and ships an OKLCH default palette, so emitting hex would be the odd choice. The v3 JavaScript config and plain CSS custom properties are both still available for projects that have not moved.

  • Your base colour is marked, not forced to 500

    A brand colour rarely sits at the exact midpoint of a scale. Forcing it to 500 — which is what most ramp generators do — quietly distorts the other ten steps. Here the nearest step is marked and the scale is left undistorted.

  • Previews carry a live verdict

    Each component preview shows the measured contrast of its text or graphic against the surface behind it, with the threshold it has to clear. Showing a palette on attractive components without saying whether the text on them is readable is exactly how a vivid 500 ends up as 16px body copy at 3.2:1.

How to use it

  1. Set the base colour

    The scale steps lightness evenly in OKLCH around it and tapers chroma at both ends.

  2. Look at the light and dark previews

    The same step behaves differently on the two surfaces, and the badges say which of them passes.

  3. Copy the @theme block

    It declares the whole scale as custom properties, which is what generates the utilities. Use the v3 export only if your build still reads a JavaScript config.

Worked example

Real input, real figures.

A button fill promoted to body text

You give it

A vivid 500 used as a text colour on a white card.

You get

The badge shows the measured ratio against the 4.5:1 threshold and it does not clear. The step two or three darker does, at the same hue — which is the whole reason the badges are on the previews rather than in a table underneath.

Against a typical Tailwind palette tool

AspectThis toolA typical palette tool
Default outputTailwind v4 @theme, OKLCHv3 JS config, hex
Base placementMarked at the nearest stepForced to 500
PreviewReal components with contrast badgesA row of swatches
ContrastMeasured against the surface behind itNot shown

Guide

Why the steps are even

The scale steps lightness evenly in OKLCH and tapers chroma at both ends. An HSL ramp built on even steps does not look even, because HSL lightness has no model of human vision in it — 50% means something very different for yellow than for blue.

Your brand colour is rarely your text colour

A vivid brand colour is built to be seen at size, on a logo. Set as 16px body copy it usually misses 4.5:1. The step two or three darker still reads as your brand and actually passes — which is what the badges on the previews are there to tell you.

Questions people ask

Straight answers. Each one links directly: copy the address after opening it.

Does this export Tailwind v4?

Yes, and it is the default. v4 moved configuration into CSS via @theme and its own default palette is OKLCH, so emitting hex would be the odd choice. The v3 JS config and plain CSS variables are both still available.

Why does my base colour not land on 500?

Because a brand colour rarely sits at the exact midpoint of a scale. We mark the step nearest your colour rather than forcing it to 500, which is what most ramp generators do and what quietly distorts the other ten steps.

What do the badges on the previews mean?

The measured contrast of that text or graphic against the surface behind it, with the threshold it has to clear. Showing a palette on attractive components without saying whether the text on them is readable is how a vivid 500 ends up as 16px body copy at 3.2:1.