Customizing the Theme
Defining brand colors, custom spacing, and fonts as CSS variables in @theme instead of a JS config file.
2 menit membaca
Tailwind's default scales (colors, spacing, font sizes) are a starting point, not a fixed vocabulary — every real project ends up adding at least a brand color or two. In Tailwind v4, this customization happens directly in CSS via the @theme directive, rather than in a separate JavaScript config file.
Defining a custom color
/* app.css */
@import "tailwindcss";
@theme {
--color-brand: #6d28d9;
--color-brand-light: #ede9fe;
}Every variable inside @theme becomes both a real CSS custom property (usable anywhere as var(--color-brand)) and a new utility class automatically. Defining --color-brand generates bg-brand, text-brand, border-brand, and every other color-based utility, exactly like Tailwind's built-in colors:
<button class="rounded-md bg-brand px-4 py-2 text-white hover:bg-brand/90">
Get started
</button>
<div class="rounded-lg bg-brand-light p-4 text-brand">Tip: this is a callout.</div>This is the key difference from v3-style configuration: there's no tailwind.config.js theme.extend.colors object to edit and no separate build step to reason about — the theme lives in the same CSS file as everything else, using a syntax (CSS custom properties) you already know.
Extending the spacing scale
@theme {
--spacing-18: 4.5rem;
}<div class="mt-18">...</div>Because --spacing-18 follows Tailwind's naming convention for the spacing namespace, it plugs into every utility that reads from that scale — margin, padding, gap, width, height — not just one of them. You get mt-18, p-18, w-18, and so on, all for one declaration.
Custom fonts
@theme {
--font-display: "Cal Sans", "sans-serif";
}<h1 class="font-display text-4xl font-bold">Launch week</h1>Why CSS variables instead of a JS object
Beyond being simpler to read, theme values defined this way are real runtime CSS custom properties — meaning you can reference var(--color-brand) from plain CSS or inline styles too, not only from generated utility classes. It also means the theme is naturally scoped to wherever you declare it; nesting an @theme override inside a specific selector is possible for cases like a themeable widget embedded in someone else's page.
Extend, don't replace, unless you mean to
Everything inside @theme is added to Tailwind's defaults by default — defining --color-brand doesn't remove blue-500 or any other built-in color. If you genuinely want to strip out the defaults and work from a bare palette (common for a strict design-system-driven product), Tailwind provides a way to reset a namespace before redefining it, but for most projects, extending the defaults with a few brand-specific additions is the right amount of customization — it keeps the whole ecosystem of examples and editor tooling built around the default scale still useful to you.