Customization
In this chapter, you learn the CSS-First way of configuring Tailwind CSS v4.
CSS-First Configuration in v4
In v4, configuration is done directly inside a CSS file. tailwind.config.js is unnecessary.
@import "tailwindcss";
@theme {
/* Customize the theme here */
}
Customizing the theme
Adding colors
@import "tailwindcss";
@theme {
/* Brand colors */
--color-brand-50: #f0f9ff;
--color-brand-100: #e0f2fe;
--color-brand-200: #bae6fd;
--color-brand-300: #7dd3fc;
--color-brand-400: #38bdf8;
--color-brand-500: #0ea5e9;
--color-brand-600: #0284c7;
--color-brand-700: #0369a1;
--color-brand-800: #075985;
--color-brand-900: #0c4a6e;
--color-brand-950: #082f49;
}
<div class="bg-brand-500 text-brand-50">Brand color</div>
Overriding an existing color
@theme {
--color-blue-500: #3b82f6; /* Change the default value */
}
Adding fonts
@theme {
--font-display: "Montserrat", sans-serif;
--font-body: "Noto Sans JP", sans-serif;
}
<h1 class="font-display">Display font</h1>
<p class="font-body">Body font</p>
Customizing spacing
The numeric spacing in v4 (p-18 / w-128, etc.) derives dynamically from --spacing (default 0.25rem), so no additional definition is needed in @theme.
<!-- Usable as-is without a definition (p-18 = 4.5rem, w-128 = 32rem) -->
<div class="p-18 w-128">Dynamic spacing</div>
If you want to change the entire scale, override --spacing itself. Only when you need a named value that cannot be expressed with the number × --spacing scale should you add it with --spacing-*.
@theme {
--spacing: 2px; /* p-4 becomes 8px */
}
Adding breakpoints
@theme {
--breakpoint-xs: 480px;
--breakpoint-3xl: 1920px;
}
<div class="xs:block 3xl:max-w-7xl">Custom breakpoint</div>
Adding shadows
@theme {
--shadow-soft: 0 2px 15px -3px rgba(0, 0, 0, 0.07),
0 10px 20px -2px rgba(0, 0, 0, 0.04);
--shadow-glow: 0 0 20px rgba(59, 130, 246, 0.5);
}
<div class="shadow-soft">Soft shadow</div>
<div class="shadow-glow">Glow shadow</div>
Adding border radii
The built-in values in v4 go up to rounded-4xl (2rem). Add larger values with --radius-*.
@theme {
--radius-5xl: 2.5rem;
}
<div class="rounded-5xl">Large border radius</div>
Adding animations
@theme {
--animate-fade-in: fade-in 0.5s ease-out;
--animate-slide-up: slide-up 0.3s ease-out;
}
@keyframes fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes slide-up {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
<div class="animate-fade-in">Fade in</div>
<div class="animate-slide-up">Slide up</div>
Custom utilities
@utility is a new directive added in v4, and it takes a different approach from @apply. @apply is a mechanism for reusing existing utility classes inside CSS, whereas @utility defines a new utility class itself. Because it can also be combined automatically with variants such as hover: and md:, it is an extension method that aligns with Tailwind's design philosophy.
The @utility directive
From v4.1, text-shadow-2xs through text-shadow-lg became built-in utilities. Choose names for your custom utilities that do not collide with the built-ins.
@utility text-shadow-hard {
text-shadow: 2px 2px 0 rgba(0, 0, 0, 0.15);
}
@utility text-glow {
text-shadow: 0 0 10px rgba(59, 130, 246, 0.6);
}
<h1 class="text-shadow-hard">Crisp text shadow</h1>
<h1 class="text-glow">Glowing text shadow</h1>
Utilities that include nesting (pseudo-elements)
@utility scrollbar-hide {
-ms-overflow-style: none;
scrollbar-width: none;
&::-webkit-scrollbar {
display: none;
}
}
Custom variants
The @custom-variant directive
/* Hover group variant */
@custom-variant hocus (&:hover, &:focus);
/* Theme attribute variant */
@custom-variant theme-midnight (&:where([data-theme="midnight"] *));
/* Custom dark mode implementation */
@custom-variant dark (&:where(.dark, .dark *));
Built-in variants such as print: work as-is without a definition.
<button class="hocus:bg-blue-600">On hover or focus</button>
<div class="print:hidden">Hidden when printing</div>
Adding plugins
You can use plugins in v4 as well. First, install them with npm.
npm install -D @tailwindcss/typography @tailwindcss/forms
@import "tailwindcss";
@plugin "@tailwindcss/typography";
@plugin "@tailwindcss/forms";
@tailwindcss/typography
<article class="prose lg:prose-xl">
<h1>Heading</h1>
<p>Body text...</p>
</article>
@tailwindcss/forms
<input type="text" class="form-input rounded-lg" />
<select class="form-select rounded-lg">
<option>Option</option>
</select>
Resetting default values
You can reset the default styles and use only your own values.
@theme {
/* Reset all colors */
--color-*: initial;
/* Define only your own colors */
--color-primary: #3b82f6;
--color-secondary: #6b7280;
--color-accent: #10b981;
}
Creating a preset
You can create a reusable theme as a CSS file.
@theme {
--color-primary-50: #eff6ff;
--color-primary-500: #3b82f6;
--color-primary-900: #1e3a8a;
--font-sans: "Inter", system-ui, sans-serif;
--font-heading: "Montserrat", sans-serif;
--radius: 0.5rem;
}
@import "tailwindcss";
@import "./preset-corporate.css";
Practical example: A corporate theme
@import "tailwindcss";
@theme {
/* Brand colors */
--color-primary-50: #f0f9ff;
--color-primary-100: #e0f2fe;
--color-primary-200: #bae6fd;
--color-primary-300: #7dd3fc;
--color-primary-400: #38bdf8;
--color-primary-500: #0ea5e9;
--color-primary-600: #0284c7;
--color-primary-700: #0369a1;
--color-primary-800: #075985;
--color-primary-900: #0c4a6e;
--color-accent-500: #10b981;
--color-accent-600: #059669;
/* Fonts */
--font-sans: "Noto Sans JP", "Inter", system-ui, sans-serif;
--font-heading: "Montserrat", sans-serif;
/* Custom shadow */
--shadow-card: 0 4px 6px -1px rgba(0, 0, 0, 0.1),
0 2px 4px -2px rgba(0, 0, 0, 0.1);
/* Custom animation */
--animate-fade-in: fade-in 0.3s ease-out;
}
@keyframes fade-in {
from { opacity: 0; transform: translateY(-10px); }
to { opacity: 1; transform: translateY(0); }
}
/* Custom utilities */
@utility card {
background-color: white;
border-radius: var(--radius-lg);
box-shadow: var(--shadow-card);
padding: var(--spacing-6);
}
@utility btn-primary {
display: inline-flex;
align-items: center;
justify-content: center;
padding: var(--spacing-2) var(--spacing-4);
background-color: var(--color-primary-500);
color: white;
border-radius: var(--radius-lg);
font-weight: 500;
transition: background-color 0.2s;
&:hover {
background-color: var(--color-primary-600);
}
}
<div class="card">
<h2 class="font-heading text-xl font-bold">Card title</h2>
<p class="mt-2 text-gray-600">Card content...</p>
<button class="btn-primary mt-4">Action</button>
</div>
CSS layers
Tailwind v4 uses CSS layers to organize styles.
@layer base {
/* Base styles */
html {
scroll-behavior: smooth;
}
body {
font-family: var(--font-sans);
}
}
@layer components {
/* Component styles */
.btn {
@apply px-4 py-2 rounded-lg font-medium transition-colors;
}
}
Custom classes inside @layer utilities from v3 and earlier are not registered as utilities in v4, and cannot use variants such as hover:. The official API for custom utilities is @utility (see "Custom utilities" earlier in this chapter).
Summary
- Customize the theme inside CSS with
@theme - Define theme variables with
--color-*/--font-*, etc. - Create custom utilities with
@utility - Create custom variants with
@custom-variant - Add plugins with
@plugin - Organize styles with
@layer - v4 takes a CSS-native approach
What to read next
- Component patterns — implement UI components using your theme
- Practical project — integrate customization in a landing page build
- Tailwind CSS Guide table of contents — back to the structure of all 18 chapters