You already know how to apply text-blue-600 or bg-gray-100. This lesson goes one level deeper: how the palette is organised, how to make any color translucent with the opacity modifier, how currentColor and inherit reduce repetition, and how to add brand colors so they behave exactly like the built-in ones. By the end you will be able to build layered, translucent interfaces and extend the palette without touching a JavaScript config file.
Tailwind ships 22 color families — five neutrals (slate, gray, zinc, neutral, stone) and seventeen hues from red through rose — plus black, white and transparent. Each family has eleven steps from 50 (lightest) to 950 (darkest).
In v4 the values are defined in the oklch color space, which keeps perceived brightness even across hues. Every step is a CSS variable such as --color-blue-500, so the same color is available in plain CSS via var(--color-blue-500).
The same name works with every color utility: text-, bg-, border-, ring-, shadow-, divide-, outline-, fill-, stroke-, accent-, caret-, decoration-, placeholder-, and the gradient stops from-, via-, to-.
To make a color translucent, append a slash and a percentage. This works on every color utility:
<div class="bg-black/50">Semi-transparent overlay</div>
<p class="text-gray-900/60">Muted paragraph</p>
<div class="border border-blue-500/30 ring-4 ring-blue-500/20">Soft outline</div>
<a class="bg-indigo-600 hover:bg-indigo-600/90">Subtle hover</a>Under the hood Tailwind produces color-mix(in oklab, var(--color-black) 50%, transparent), so the result is a real translucent color rather than an opacity property on the whole element. That distinction matters: opacity-50 fades the element and all of its children, while bg-white/50 only affects the background.
Any percentage is allowed (/15, /33, /85), and arbitrary values work too: bg-blue-500/[0.37].
Three special values save a lot of duplication:
<!-- The SVG takes the color of the surrounding text -->
<button class="text-red-600 hover:text-red-800">
<svg class="size-5 fill-current" viewBox="0 0 20 20">...</svg>
Delete
</button>
<!-- Borders and rings that follow the text color -->
<span class="text-sky-700 border border-current rounded px-2">Tag</span>
<!-- Inherit the parent's color; useful inside prose blocks -->
<a class="text-inherit underline">Link</a>In v4 the default border color is already currentColor, so a plain border picks up the text color unless you set border-gray-200 explicitly. bg-transparent and text-transparent (often combined with bg-clip-text for gradient text) round out the set.
Custom colors are declared as --color-* variables inside an @theme block in your main CSS file. Once defined they get every utility, every variant and the opacity modifier automatically:
@import "tailwindcss";
@theme {
--color-brand-50: oklch(0.97 0.02 260);
--color-brand-500: oklch(0.65 0.18 260);
--color-brand-600: oklch(0.58 0.18 260);
--color-brand-900: oklch(0.3 0.12 260);
--color-surface: #f8fafc;
}Now bg-brand-500, hover:bg-brand-600/90, text-brand-900 and border-surface all exist. Hex, rgb(), hsl() and oklch() are all valid. To replace the whole palette rather than extend it, reset the namespace first with --color-*: initial; and then declare your own colors.
bg-opacity-50 or text-opacity-75 — they were removed in v4. Use the /50 modifier.opacity-* to dim a background; it dims the text as well.--brand: ... outside @theme. Plain variables do not generate utilities; only --color-* inside @theme does.border-gray-200 (or similar) where you want a light divider.What CSS does `bg-red-500/25` generate in Tailwind v4?
50–950, defined in oklch and exposed as --color-* variables./percentage to any color utility for transparency; it uses color-mix() and does not affect children.fill-current, border-current and text-inherit let colors follow the surrounding text.--color-name-step inside @theme; they gain every utility and variant automatically.*-opacity-* utilities are gone; use the slash modifier instead.Next lesson: Spacing: Margin, Padding and Sizing — control space inside and around elements with the spacing scale.