How to use Tailwind v4 to superpower your design system.
Back to Journals Back to Journals

How to use Tailwind v4 to superpower your design system.

4 min read

|

After four years of using Tailwind CSS across everything from complex web applications to React Native mobile apps, I’ve watched it evolve from a clever utility framework into something much more powerful. The 2024 release of Tailwind V4 represents a fundamental shift—transforming Tailwind from a collection of predefined classes into a dynamic design system engine.

This isn’t just another framework update. V4 reimagines how we think about styling, design tokens, and component systems. If you’ve been using Tailwind V3, prepare to rethink everything you know about utility-first CSS.

What makes Tailwind different

Unlike component libraries like Bootstrap or Material UI, Tailwind doesn’t make design decisions for you. Instead of <Button variant="primary">, you get building blocks like bg-blue-500 text-white px-4 py-2 rounded. This approach gives you complete control while maintaining consistency through design tokens.

<div class="bg-red-500 w-24 h-24 p-6"></div>

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.

The V4 revolution: From utilities to engine

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.

Theming with tokens

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:

V4: The new way

@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

Building dynamic utility systems

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.

Functional utilities with wildcards

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.

Building contextual component systems

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.

Advanced techniques with CSS if()

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.

Contextual component classes:

https://play.tailwindcss.com/tA1RpdM4oD

Color Mixing

https://play.tailwindcss.com/k4P2LMCuHm

Contextual component classes

https://codesandbox.io/p/devbox/4vzjsz

What We’ve Learned

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.