Tailwind v4 Colors: Add & Customize Fast
Learn to add and customize colors in Tailwind v4
Last updated: 24 July 2025 • Compatible with Tailwind v4.1
Tailwind v4 rewired the way colors are defined, shipped, and overridden. Everything is now CSS‑first and token‑driven: every design token becomes a custom property at build‑time, and new @theme
blocks replace most of the old tailwind.config.js
color tweaks. This tutorial walks you through every change from v3 ➜ v4 and provides copy‑paste examples for the common tasks—extending palettes, replacing them, theming with CSS variables, and even stripping defaults you don’t use.
1. What actually changed in v4?
Area | v3 behavior | v4 behavior |
---|---|---|
Token storage | Static JS object in | Custom properties generated under |
Default palette | sRGB‑based palette with 22 color families | OKLCH‑based palette with perceptually even steps |
Extending colors |
| Wrap new values in a |
Disabling defaults | Import | Use |
Runtime theming | Manually duplicate variables | All tokens available as CSS variables out‑of‑the‑box |
2. Adding a new brand color (keep the defaults)
/* app.css */
@import "tailwindcss";
@theme {
/* Your brand primary */
--color-primary-50: oklch(98.3% 0.02 250);
--color-primary-100: oklch(95.1% 0.03 250);
--color-primary-500: oklch(68% 0.1 250);
}
You can now drop utilities like bg-primary-500
or text-primary-50
anywhere in your markup. Because the color lives in a CSS variable, you can hot‑swap it later with a simple runtime override.
When you don’t need a full scale
If you only need a single shade, just define one variable:
@theme { --color-accent: #FF5A1F; }
Tailwind auto‑generates bg-accent
, text-accent
, border-accent
, etc.
3. Overriding default colors
Want to keep Tailwind’s scale but shift the hue? Replace just the swatch you need:
@theme {
/* Warmer gray */
--color-gray-400: oklch(75% 0.02 80);
}
Every class that referenced gray‑400
now renders the warmer tone.
Disabling entire families
@tailwind base;
@theme {
--disable-color-teal: true;
--disable-color-orange: true;
}
The compiler removes those utilities entirely, shrinking your CSS bundle.
4. Replacing the whole palette (slimming builds)
/* Full takeover — no defaults */
@tailwind base;
@theme {
--disable-default-colors: true;
/* Brand palette */
--color-brand-50: #F5F5FA;
--color-brand-100: #EAEAFA;
--color-brand-900: #0D0D3B;
}
After this, utilities are generated only for your brand colors. Perfect for design‑system packages where every kilobyte counts.
5. Runtime theming with CSS variables
Because tokens are regular custom properties, you can theme with pure CSS:
<html class="dark">
<body class="bg-surface text-content">
...
</body>
</html>
<style>
/* Light */
@theme {
--color-surface: #FFFFFF;
--color-content: #111827;
}
/* Dark */
html.dark @theme {
--color-surface: #1F2937;
--color-content: #F9FAFB;
}
</style>
No additional plugins needed—just toggle the dark
class at run‑time.
6. OKLCH cheat‑sheet
Hex | OKLCH | Equivalent utility |
---|---|---|
|
|
|
|
|
|
Use a converter like oklch.com or npm i oklch
to generate your palette.
7. Other color‑related changes worth noting
Border and placeholder colors now inherit
currentColor
by default .Color naming best practice is still literal (
red‑500
) but you can choose abstract names if theming multiple brands .You can target Shadow DOM components by exporting tokens under
:root, :host
selectors in an@theme
block .
TL;DR for Migrators
Delete your color section in
tailwind.config.js
.Import
@tailwind
at the top of your CSS entry file.Add an
@theme
block with any new colors or overrides.Run
npx tailwindcss -o app.css --minify
and enjoy leaner builds.
Happy theming! ✨
FAQ
Is OKLCH backward compatible with old browsers?
Tailwind v4 targets Safari 16.4+, Chrome 111+, and Firefox 128+, all of which fully support OKLCH.
Can I still use tailwind.config.js?
Yes, but it’s now optional for colors. Use it for other settings like breakpoints, plugins, or JIT safelists.
How do I disable color autocompletion noise?
Set --disable-default-colors: true or disable individual families as shown earlier.
Can I use arbitrary color values like bg-[#1e40af] in v4?
Yes—JIT arbitrary‑value syntax is unchanged, and the compiler still tree‑shakes those single‑use utilities.
Do I still need PostCSS to process @theme?
Yes; @theme is a Tailwind‑specific at‑rule that the CLI/PostCSS plugin expands during build.
How can I ship separate light and dark palettes?
Declare two @theme blocks—one scoped to html (light) and another to .dark (or @media (prefers-color-scheme: dark))—and toggle as needed.
Is there a limit to how many custom colors I can add?
No practical limit; the compiler generates utilities for every variable you declare, though more tokens slightly increase build size.
What’s the best naming convention for semantic colors?
Use semantic variable names like --color-surface but expose them through utilities such as bg-surface so designers think in intent while developers keep class ergonomics.

Yucel is a digital product creator and content writer with a knack for full-stack development. He loves blending technical know-how with engaging storytelling to build practical, user-friendly solutions. When he's not coding or writing, you'll likely find him exploring new tech trends or getting inspired by nature.