New Color System
Tailwind v4 overhauls the color system with two significant changes: a migration to OKLCH color space and a shift in how the default color palette is structured.
OKLCH: Why It Matters
OKLCH (Oklab Lightness Chroma Hue) is a perceptually uniform color space that produces more consistent brightness across hues. The practical effect is that Tailwind v4’s default colors look better at every point in the scale — the 500-shade of every color has genuinely similar perceived brightness, which wasn’t true with the HSL-based v3 palette.
Browser support for OKLCH is now over 96% globally (as of early 2026), which is why Tailwind v4 uses it as the primary color format. Lightning CSS automatically transforms OKLCH values for older browsers that need it.
Color Palette Changes
The v4 palette drops several rarely-used colors (warm gray, cool gray, true gray, blue gray as separate palettes) and consolidates to a cleaner set. The semantic color classes border-DEFAULT and similar patterns also change:
/* v3 */
<div class="border-gray-200 text-gray-900">
/* v4 — same visual result, cleaner semantics */
<div class="border-zinc-200 text-zinc-900">
The migration codemod handles most color renames automatically.
Composable Variants
Tailwind v4 introduces composable variants — a new system for combining variant modifiers that was impossible in v3 without plugins.
What Composable Variants Enable
/* v4: group and peer variants now stack cleanly */
<div class="group">
<p class="group-hover:group-focus-within:text-blue-500">
Turns blue when parent is both hovered AND has focused child
</p>
</div>
/* v4: data attribute variants */
<div data-state="active" class="data-[state=active]:bg-blue-100">
/* v4: arbitrary variants */
<div class="[&:nth-child(3)]:bg-red-100">
New Built-in Variants in v4
starting: — the CSS @starting-style rule for entry animations
not-* — inverses for most state variants (not-hover:, not-focus:)
in-* — descendant variants that target the component itself based on ancestor state
**: — applies utilities to all descendants
/* v4: entry animation with @starting-style */
<div class="opacity-100 starting:opacity-0 transition-opacity">
Fades in on mount
</div>
Breaking Changes from v3
This section covers every significant breaking change with before/after examples. Read this carefully before migrating.
1. Opacity Utilities
The /opacity modifier syntax for colors has changed internally, but the class syntax is the same. However, the standalone opacity utilities (opacity-50, etc.) on colored backgrounds now behave differently due to the color-mix approach.
/* v3 — these classes still work in v4 */
<div class="bg-blue-500/50"> /* 50% opacity blue */
/* But: text-opacity-*, bg-opacity-* utilities are removed in v4 */
/* v3 */
<p class="text-blue-500 text-opacity-75">
/* v4 equivalent */
<p class="text-blue-500/75">
2. Border Defaults Changed
In v3, border defaulted to a 1px solid border with the color currentColor. In v4, the default border color is explicitly the current border-color CSS variable value, which may differ from currentColor.
/* v3 — border color defaulted to a specific gray */
<div class="border"> /* Used gray-200 by default */
/* v4 — border uses --color-border CSS variable */
<div class="border"> /* Uses your @theme --color-border value */
/* To maintain exact v3 behavior, add to your @theme: */
@theme {
--color-border: var(--color-zinc-200);
}
3. Ring Width Default Changed
The ring utility in v3 applied a 3px ring by default. In v4, it defaults to 1px, matching ring-1 behavior.
/* v3 — ring was 3px */
<button class="focus:ring"> /* 3px ring */
/* v4 — ring is now 1px */
<button class="focus:ring"> /* 1px ring */
/* To maintain v3 behavior in v4: */
<button class="focus:ring-3"> /* explicit 3px */
4. Shadow Colors Are Now Transparent by Default
In v3, box shadows had opaque black colors by default. In v4, shadow colors are transparent and must be explicitly set or use the new color utilities.
/* v3 — shadow had visible dark color */
<div class="shadow-lg">
/* v4 — shadow is transparent unless you set color */
<div class="shadow-lg shadow-black/10"> /* explicit color */
/* Or configure a default in @theme: */
@theme {
--shadow-color: rgba(0, 0, 0, 0.1);
}
5. PostCSS Plugin Import Changed
/* v3 postcss.config.js */
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
}
}
/* v4 postcss.config.js — different package */
module.exports = {
plugins: {
'@tailwindcss/postcss': {},
/* autoprefixer is no longer needed — Lightning CSS handles it */
}
}
6. Configuration File Removal
If you have a tailwind.config.js, it is no longer automatically loaded. You must either migrate to @theme in CSS, or use the compatibility mode explicitly.
Migration: Using @tailwindcss/upgrade
Tailwind provides an official migration codemod that handles many of the changes automatically:
npx @tailwindcss/upgrade
The codemod performs these transformations automatically:
- Converts
tailwind.config.js to @theme directives in your main CSS file
- Updates
postcss.config.js to use @tailwindcss/postcss
- Renames removed color classes (
text-opacity-* → text-*/ syntax)
- Updates deprecated utility names
- Converts
@tailwind base/components/utilities directives to the new @import "tailwindcss" syntax
After running the codemod, you will likely still need to manually address:
- Custom plugins written in JavaScript that depend on the old config structure
- Ring and shadow color expectations in your design
- Any dynamic theme manipulation that read from tailwind.config.js at runtime
- Storybook and testing setup that references the config file directly
Migration Checklist
- Run
npx @tailwindcss/upgrade and review the diff carefully
- Update the PostCSS config (
tailwindcss → @tailwindcss/postcss, remove autoprefixer)
- Install the new packages:
npm install tailwindcss@4 @tailwindcss/postcss
- Remove the old packages:
npm uninstall tailwindcss postcss-import autoprefixer
- Move your
@tailwind base/components/utilities lines to @import "tailwindcss"
- Verify all custom colors, fonts, and spacing work as expected in the browser
- Check focus rings, borders, and shadows in your UI components
- Run your test suite (especially visual regression tests if you have them)
Performance Benchmarks: v3 vs v4 in Production
Beyond build speed, v4 also produces smaller CSS output. The new engine is more aggressive about removing unused styles, and the composable variant system avoids generating duplicate CSS for variant combinations.
| Metric |
Tailwind v3 |
Tailwind v4 |
| Initial build |
7.2s (large project) |
1.3s (large project) |
| Incremental rebuild |
340ms |
44ms |
| CSS output size |
28KB gzipped |
21KB gzipped |
| CSS variable count |
~180 |
~420 (more expressive) |
The larger CSS variable count in v4 is intentional — every design token is available as a variable. Despite the higher variable count, the final CSS output is smaller because the utility class generation is more efficient.
People Also Ask
Do I need to remove tailwind.config.js when upgrading to v4?
Yes, eventually. Tailwind v4 no longer automatically reads tailwind.config.js. The upgrade codemod (npx @tailwindcss/upgrade) will migrate your config to the new @theme CSS-first format automatically. You can keep the old config file around temporarily, but it has no effect unless you explicitly use the v4 compatibility config adapter (which is intended as a temporary migration aid, not a permanent solution).
Is Tailwind CSS v4 compatible with older browsers?
Tailwind v4 targets the same browser support as v3 (modern browsers, generally >95% global coverage). Lightning CSS handles the transformation of modern CSS features like OKLCH colors, logical properties, and nesting to formats that older browsers understand. You do not need to configure PostCSS plugins for this — it’s built into the Lightning CSS compilation pipeline. Browser support targets can be configured in your Browserslist configuration.
Can I still use CSS-in-JS libraries with Tailwind v4?
Yes, and the experience is actually better in v4. Because design tokens are now proper CSS custom properties defined in @theme, you can reference them in CSS-in-JS as regular CSS variables (var(--color-brand-500)) without any special integration. In v3, you had to import the JavaScript config and extract values — a much more fragile pattern.
Should You Upgrade Now?
If you’re starting a new project, use Tailwind v4. There’s no reason to start with v3.
If you have an existing v3 project, the upgrade is worth it, but plan for it carefully. The codemod handles 80-90% of the migration automatically. The remaining 10-20% — custom plugins, complex theme configurations, visual regression differences — requires manual attention. For small to medium projects, budget 2-4 hours. For large, heavily customized projects, budget a full sprint.
The speed improvements alone justify the migration cost for most active projects. Sub-50ms incremental rebuilds change the development experience measurably.
Want to skip months of trial and error? We have distilled thousands of hours of prompt engineering into ready-to-use prompt packs that deliver results on day one. Our packs at wowhow.cloud include battle-tested prompts for marketing, coding, business, writing, and more — each one refined until it consistently produces professional-grade output.
Blog reader exclusive: Use code BLOGREADER20 for 20% off your entire cart. No minimum, no catch.
Browse Prompt Packs
Comments · 0
No comments yet. Be the first to share your thoughts.