What is color-mix()?

color-mix(): The CSS color-mix() function blends two colors by percentage in a chosen color space, for example an accent mixed with transparent to tint it from one token.

color-mix(in oklch, var(--accent) 20%, transparent) produces the accent color at 20 percent opacity. color-mix(in oklch, var(--accent), white 30%) lightens it; color-mix(in oklch, var(--warning) 70%, var(--fg)) darkens a warning yellow toward the text color until it is readable. The function takes a color space, two colors and optional percentages, and returns the blend. Its value is that the inputs can be CSS variables, which means hover states, tints, borders and alpha variants can be derived from a token at runtime instead of being hand-picked and stored as more tokens. It is supported in most browsers.

How it works

css
.button {
  background: var(--accent);
}
.button:hover {
  background: color-mix(in oklch, var(--accent) 88%, black);
}
.chip {
  background: color-mix(in oklch, var(--accent) 12%, transparent);
  border-color: color-mix(in oklch, var(--accent) 30%, transparent);
  color: color-mix(in oklch, var(--accent) 70%, var(--fg));
}
  • The color space matters. Mixing in srgb darkens and desaturates through gray; mixing in oklch or oklab keeps the perceived lightness and hue steadier, which is why MiniDev mixes in OKLCH. Mixing with transparent is the one case where the space barely matters.
  • Percentages normalize. If only one is given, the other is the remainder. If both are given and do not sum to 100, they are scaled to it; if they sum to less than 100, the result also picks up that much transparency.
  • Hue interpolation in polar spaces can take the shorter hue or longer hue route; the default, shorter, is almost always right.
  • It is a computed value, so it works inside custom properties and transitions, and it animates when both inputs are colors.

Where it earns its place

  • Opacity variants of a token: bg-accent/10 in Tailwind CSS v4 compiles to a color-mix() with transparent, which is how opacity modifiers work on variable-based colors.
  • State colors derived from a base: hover, active and disabled shades of a brand color that changes per customer.
  • Readable text on tinted backgrounds, by mixing the tone color toward the foreground until it clears WCAG contrast.
  • Theming with one input. A customer picks one accent; every tint, border and soft background follows in both light and dark mode.

Relative color syntax

The newer relative color syntax, oklch(from var(--accent) l c h / 0.2), edits one channel of a color directly, such as its lightness, and is more precise than mixing when you know the target. It is available in most current browsers but arrived later than color-mix(), so for an alpha or a tint color-mix() remains the safe choice, and for channel math the relative syntax is cleaner where you can use it.

In MiniDev

MiniDev UI derives most tinted surfaces this way. StatusBadge sets its warning text to color-mix(in oklch, var(--warning) 70%, var(--fg)) so yellow stays readable on a pale yellow background, and the light-following effects behind LightProvider fade the accent into transparent with a mix rather than a second variable. ThemePicker and ColorPicker are where a single accent gets chosen; everything downstream mixes from it. The OKLCH colors in Tailwind v4 guide walks through the palette.

Status BadgeuiTailwind status badge with a tinted fill, hairline border and colored dot in neutral, success, warning, danger, accent and info tones that read as one set.npx shadcn@latest add @minidev/status-badgeLight ProvideruiA page wide light source that follows the pointer and drifts when idle, driving shadows via CSS variables, plus a hairline, glass, metal and paper switcher.npx shadcn@latest add @minidev/light-provider