Out of the box, Tailwind CSS gives you an excellent generic design system. But your brand is not generic: it has its own colors, fonts, and spacing personality. In this lesson you will learn how to customize the theme, when to extend versus override, and how one-off arbitrary values fit into the picture.
In Tailwind v4, the theme is configured directly in your CSS file with the @theme directive:
@import "tailwindcss";
@theme {
--color-brand: #4f46e5;
--color-brand-dark: #3730a3;
--font-display: "Poppins", sans-serif;
--spacing-18: 4.5rem;
}Every variable you declare automatically generates matching utilities: bg-brand, text-brand-dark, font-display, p-18, and so on. In Tailwind v3 projects you achieve the same result in tailwind.config.js under theme.extend — the concepts are identical, only the location differs.
This distinction matters:
bg-brand works, and bg-blue-500 still works too.--color-* set with the defaults reset, and only your colors exist — useful for strict design systems where nobody should ever reach for bg-pink-300.For most projects, extend. Override only when a design team explicitly wants to forbid off-palette choices.
Do not stop at one hex value. Give brand colors a shade scale so they compose with the rest of Tailwind:
@theme {
--color-brand-50: #eef2ff;
--color-brand-500: #4f46e5;
--color-brand-600: #4338ca;
--color-brand-900: #312e81;
}Now bg-brand-50 works for subtle backgrounds and hover:bg-brand-600 for button states, mirroring how the built-in palette behaves.
Load the font (for example from Google Fonts) in your HTML, then register it:
@theme {
--font-sans: "Inter", ui-sans-serif, system-ui, sans-serif;
--font-display: "Poppins", sans-serif;
}Overriding --font-sans changes the default body font everywhere; font-display becomes an opt-in utility for headings.
For true one-offs, square brackets inject any CSS value without touching the theme:
<div class="bg-[#1da1f2] w-[137px] top-[117px] grid-cols-[1fr_2fr]">Rule of thumb: if you use an arbitrary value three or more times, promote it to the theme. Arbitrary values scattered everywhere defeat the consistency that makes Tailwind valuable.
When you need a utility Tailwind does not ship, define it with @utility so it works with every variant:
@utility scrollbar-hidden {
&::-webkit-scrollbar { display: none; }
scrollbar-width: none;
}Official plugins extend the system further: @tailwindcss/typography for prose, and @tailwindcss/forms for sane form control resets.
@theme with meaningful names.Teams that follow this order end up with small, intentional configs instead of sprawling ones.
@theme; v3 uses tailwind.config.js — same ideas.--color-brand gives bg-brand, text-brand).Next up: Reusable Components and @apply, where you will tame repeated utility strings.