Tailwind scans your markup and generates only the CSS you actually use:
.bg-red-500 { background-color: var(--color-red-500);}
.w-24 { width: calc(var(--spacing) * 24);}
.h-24 { height: calc(var(--spacing) * 24);}
.p-6 { padding: calc(var(--spacing) * 6);}
This approach eliminates dead CSS and creates smaller bundles. More importantly, utility classes function like design tokens—they enforce consistency across your entire application.
Here’s where V4 gets interesting. Instead of extending a config file with your design tokens, V4 lets you define tokens as CSS variables and automatically generates utilities from them. The framework becomes a design system compiler.
Before v4, we had to create tokens separately and then configure the config file to consume them.
@tailwind base;@tailwind components;@tailwind utilities;
:root { --color-primary: #fff; --color-secondary: #000;}
module.exports = { theme: { extend: { colors: { "color-primary": "var(--color-primary)", "color-secondary": "var(--color-secondary)" }, }, },};
This gave you bg-primary and text-secondary classes, but required maintaining two separate files.
<div class="bg-color-primary text-color-secondary"></div>
Tailwind scans your markup and generates only the CSS you actually use:
@import "tailwindcss";
@theme { --color-primary: #fff; --color-secondary: #000;}
That’s it. No config file needed. Define a CSS variable with the right prefix, and Tailwind automatically generates utilities. --color-primary
becomes bg-primary
, text-primary
, border-primary
, and dozens of other utilities.
You can read more about the default theme variables Tailwind offers here - https://tailwindcss.com/docs/theme#default-theme-variable-reference. Variables are namespaced so the engine can generate the correct CSS properties: https://tailwindcss.com/docs/theme#theme-variable-namespaces
V4’s real power emerges when you start creating your own utility systems. The @utility
directive lets you define custom utilities that integrate seamlessly with Tailwind’s ecosystem.
@utility content-auto { content-visibility: auto;}
Now you can use content-auto
, hover:content-auto
, lg:content-auto
, and all the variants work automatically. No need to define different states or classes.
This is where things get exciting. You can create utilities that dynamically generate based on your design tokens.
@theme { --tab-size-2: 2; --tab-size-4: 4; --tab-size-github: 8;}
@utility tab-* { tab-size: --value(--tab-size-*);}
This creates tab-2
, tab-4
, and tab-github
utilities automatically. Need a new variant? Add another CSS variable. No class definitions, no build process changes.
The --value()
function is used to resolve CSS variables defined in your theme.
V4 enables something I call “contextual components”—utilities that adapt based on themes, screen sizes, or user preferences without writing media queries in your markup. The only ability that Tailwind enables here is dynamic class generation, but everything else is standard CSS variable behaviour.
/* Define base tokens */@theme { --color-background: #fff; --color-text: #121212; --card-padding-sm: 4px; --card-padding-md: 8px; --card-padding-lg: 16px; --card-padding-xl: 24px;}
/* Adaptive behavior */:root { [data-theme="dark"] { --color-background: #181818; --color-text: #fafafa; }
@media (min-width: 768px) { --card-padding-sm: 6px; --card-padding-md: 12px; --card-padding-lg: 20px; --card-padding-xl: 32px; }}
/* Component utility */@utility card-* { background-color: var(--color-background); color: var(--color-text); padding: var(--card-padding-*); border-radius: calc(var(--spacing) * 2);}
Now card-sm
, card-md
, and other classes are automatically created, and adjust their padding based on screen size and switches colors in dark mode. One class definition for contextual behavior.
The CSS if()
function (currently Chrome/Edge only, but coming to all browsers) opens up even more possibilities when combined with V4’s token system.
https://play.tailwindcss.com/tA1RpdM4oD
https://play.tailwindcss.com/k4P2LMCuHm
https://codesandbox.io/p/devbox/4vzjsz
The shift from utility-first to token-first thinking takes adjustment, but the payoff in maintainability and flexibility is substantial. Once you experience the power of dynamic utility generation, going back to static configurations feels limiting.
Tailwind V4 isn’t just an upgrade—it’s a new paradigm for building design systems. The question isn’t whether you should adopt it, but how quickly you can rethink your approach to CSS architecture.
Ready to dive deeper? Start experimenting with the examples above, and discover how V4 can transform your design system from a collection of styles into a dynamic, responsive foundation for your entire application.