✳️ 681+ shadcn/ui Blocks, lifetime updates, unlimited projects — Get 50+ fresh blocks every month ✳️ 👇
See Components →

Tailwind v4 Colors: Add & Customize Fast

Learn to add and customize colors in Tailwind v4

by Yucel F. Sahan
3 min read
Updated on

Tailwind CSS v4 Colors

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 tailwind.config.js

Custom properties generated under --color-* via @theme

Default palette

sRGB‑based palette with 22 color families

OKLCH‑based palette with perceptually even steps

Extending colors

module.exports = { theme: { extend: { colors: { brand: {...} }}}}

Wrap new values in a @theme block in any CSS file

Disabling defaults

Import colors util and delete keys

Use @tailwind base; + @theme { --disable-default-colors: true; }

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.

Tailwind color palette example

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

#2563EB

oklch(62% 0.19 254)

bg-blue-600

#FACC15

oklch(90% 0.16 99)

text-yellow-400

Use a converter like oklch.com or npm i oklch to generate your palette.

  • 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

  1. Delete your color section in tailwind.config.js.

  2. Import @tailwind at the top of your CSS entry file.

  3. Add an @theme block with any new colors or overrides.

  4. 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 F. Sahan

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.