The word “tailwind” literally means the wind blowing in the same direction as a plane or boat’s course of movement. It helps an object travel faster and reach its destination quicker, ensuring speed and efficiency.
Tailwind CSS is a utility-first framework that lets you “rapidly build modern websites without leaving your HTML.” It’s not every developer’s cup of tea, but Tailwind CSS has gained significant popularity since its release in 2019.
Today, you’ll likely find Tailwind CSS listed alongside established names like Bootstrap and Bulma when you search for “Top [insert number] CSS frameworks.”
This article will provide a preview and in-depth analysis of the next version, Tailwind v4.0. We’ll cover strategies for migrating existing projects and examples demonstrating the new features of Tailwind v4.0. We’ll also compare it with similar CSS frameworks, and explore the benefits and limitations of using this framework.
Getting started with Tailwind v4.0
Tailwind v4.0 has been in development for several months, and the first public beta version was released in November 2024.
For more detailed information, you can visit the prerelease documentation, but this guide will highlight some of the many new and exciting features developers can look forward to in Tailwind CSS v4.0
The Tailwind team announced a new performance engine, Tailwind Oxide, in March 2024. Some benefits include a unified toolchain and simplified configuration to speed up the build process.
CSS-first configuration
With the current Tailwind version, the tailwind.config.js
file allows you to override Tailwind’s default design tokens. It’s a customization hub where you can add custom utility classes and themes, disable plugins, and more.
Its most important function is defining the content sources for your project so Tailwind can scan for relevant utility class names and produce the right output.
Here’s the default code for the tailwind.config.js
file when setting up a new project with Tailwind v3:
/** @type {import('tailwindcss').Config} */
export default {
content: [
"./index.html",
"./src/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}
Removed directives
After setting up the config file, the next step involved adding the Tailwind directives to the index.css
file.
These are the directives in Tailwind v3:
@tailwind base;
@tailwind components;
@tailwind utilities;
In Tailwind v4, you don’t need a tailwind.config.js
file and @tailwind
directives. You’ll only need to import "tailwindcss"
into your main CSS file, and you’re good to go:
@import "tailwindcss";
This reduces the number of steps when setting up a new project and the number of files.
You can still use a JS config file, for example, if you already have an existing v3 project, by using the new @config
directive to load it in your CSS file:
@import "tailwindcss";
@config "../../tailwind.config.js";
However, not every feature, like corePlugins
, important
, and separator
, is likely to be supported in the full v4.0 release. Some options, like safelist
may return with changes in behavior.
Source detection
If there are files you don’t want to include, you can use the source()
function when importing Tailwind to limit automatic detection:
@import "tailwindcss" source("../src");
For additional sources that Tailwind doesn’t detect by default, like anything in your .gitignore
file, you can add them using the @source
directive:
@import "tailwindcss";
@source "../node_modules/@my-company/ui-lib/src/components";
You can also disable source detection entirely:
@import "tailwindcss" source(none);
Disabling preflight
You can import the specific individual layers you need for your project and disable Tailwind’s base styles:
@layer theme, base, components, utilities;
@import "tailwindcss/theme" layer(theme);
@import "tailwindcss/utilities" layer(utilities);
Customizing themes
The new CSS-first approach makes adding custom styling to your Tailwind project easier. Any customization will be added directly to the main CSS file instead of a JavaScript configuration file.
If, for instance, you want to configure new colors for a custom theme in Tailwind CSS v3, you’ll need to define the new utility classes in the theme
section of the tailwind.config.js
file.
Here’s how you’d do it in the JavaScript configuration file:
/** @type {import('tailwindcss').Config} */
export default {
content: [
"./index.html",
"./src/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {
colors: {
background:'#764abc',
lilac: '#eabad2',
light: '#eae3f5'
}
},
},
plugins: [],
}
Here’s how you would add the classes to your HTML file:
<div className="bg-background">
<header className="flex justify-between py-4 px-8">
<a href="/" className="text-light">LogRocket - Oscar</a>
<ul className="text-lilac">
<li><a href="#">Home</a></li>
<li><a href="#">About</a></li>
<li><a href="#">Contact</a></li>
</ul>
</header>
In this example, the utility classes are bg-background
, text-light
, and text-lilac
.
In Tailwind CSS v4.0, you configure all your customizations in CSS with the new @theme
directive:
@import "tailwindcss";
@theme {
--color-background-100: #764abc;
--color-lilac-100: #eabad2;
--color-light-100: #eae3f5;
}
The utility classes are then added to the HTML. You can choose to have different shades of the same color like the default Tailwind colors:
<div className="bg-background-100">
<header className="flex justify-between py-4 px-8">
<a href="/" className="text-light-100">LogRocket - Oscar</a>
<ul className="text-lilac-100">
<li><a href="#">Home</a></li>
<li><a href="#">About</a></li>
<li><a href="#">Contact</a></li>
</ul>
</header>
If you’re testing it out with VS Code, the @import
directive may be highlighted as an error but don’t worry, it’ll work just fine.
Note that the examples above were created with Tailwind CSS and React, hence why we have className
in the HTML and not class
. The utilities remain the same no matter the framework you’re working with.
Theme variables
From the previous example, you can see that CSS variables drive all theme styling in Tailwind v4.0:
@theme {
--font-display: "Poppins", "sans-serif";
--ease-fluid: cubic-bezier(0.3,0,0,1);
--color-background-100: #764abc;
}
In v4.0, you can override a specific theme namespace — that is, the default utilities for colors, fonts, text, and more, or the entire Tailwind theme and configure your own. You can easily configure custom styling for essentially every Tailwind utility in the main CSS file:
To override the entire default theme, use --*: initial
. If you wanted to override the default Tailwind font and define your own, you’d use --font-*: initial
followed by your custom styling:
@import "tailwindcss";
@theme {
--font-*: initial
--font-display: "Poppins", "sans-serif";
}
In this case, font-display
will be the only font-family
utility available in your project.
You can set default styling for a custom property using double-dashes. Here’s a page with the default Tailwind CSS font and text styling:
Here’s the HTML markup for this page:
<div className="bg-background h-screen">
<header className="flex justify-between py-4 px-8">
<a href="/" className="text-lg text-light font-bold">LogRocket - Oscar</a>
<ul className="hidden md:flex flex- items-center align-middle gap-4 font-bold text-lilac">
<li>
<a href="#" className="py-2 px-4 rounded-md">Home</a>
</li>
<li><a href="#" className="">About</a></li>
<li><a href="#" className="">Contact</a></li>
</ul>
</header>
<div className="container px-32 py-32">
<div className="flex">
<div>
<h1 className="text-5xl text-lilac font-bold">Tailwind CSS</h1>
<br />
<h3 className="text-3xl text-light font-semibold">
Build websites with utility classes from the comfort of your HTML
</h3>
<br />
<p className="text-2xl text-light">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Fu gi at veniet atque unde laudantium. Ipsa nam quisquam quod non fficiis porro? Lorem ipsum dolor, sit amet consectetur adipisicing elit. Eos iure nemo a hic sunt incidunt?
</p>
</div>
</div>
</div>
</div>
We’re using the custom colors from the earlier example, and configuring new font and text styling:
@import "tailwindcss";
@import url('https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap');
@theme {
--font-display : "Poppins", sans-serif;
--font-logo: "Roboto", sans-serif;
--text-logo: 1.5rem;
--text-logo--font-weight: 700;
--text-big: 6rem;
--text-big--font-weight: 700;
--text-big--letter-spacing: -0.025em;
--color-background-100: #764abc;
--color-lilac-100: #eabad2;
--color-light-100: #eae3f5;
}
In this example, we’re importing two fonts and saving them under the --font-display
and --font-logo
variables, to be used for the logo and h1
header. We’re also configuring new text sizes and default styling for both.
So, when you add the utility class text-logo
in your HTML, the element will have a font size of 1.5rem
and font-weight
of 700
by default. Similarly, any element with the class name, text-big
, will have a font-size
of 6rem
, font-weight
of 700
, and letter-spacing
of -0.025em
by default.
Now we add the new utility classes into the HTML file:
<div className="bg-background-100 h-screen">
<header className="flex justify-between py-4 px-8">
<a href="/" className="font-logo text-logo text-light-100">LogRocket - Oscar</a>
<ul className="hidden md:flex flex items-center align-middle gap-4 font-display text-lilac-100">
<li>
<a href="#" className="py-2 px-4 rounded-md">Home</a>
</li>
<li><a href="#" className="">About</a></li>
<li><a href="#" className="">Contact</a></li>
</ul>
</header>
<div className="container px-32 py-32 font-display">
<div className="flex">
<div>
<h1 className="text-lilac-100 text-big">Tailwind CSS</h1>
<br />
<h3 className="text-3xl text-light-100">
Build websites with utility classes from the comfort of your HTML
</h3>
<br />
<p className="text-2xl text-light">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Fu gi at veniet atque unde laudantium. Ipsa nam quisquam quod non fficiis porro? Lorem ipsum dolor, sit amet consectetur adipisicing elit. Eos iure nemo a hic sunt incidunt?
</p>
</div>
</div>
</div>
</div>
Here’s a screenshot of the page with the custom styling:
In Tailwind v4.0, there will be less dependency on the default Tailwind values as multiple classes can be replaced with one custom utility. In our example, the text-big
class name replaces the text-5xl
and text-bold
utility classes for the h1
header.
Again, this isn’t limited to specific namespaces — you can do this with every utility.
Simplified theme configuration
Some utilities are no longer based on your theme configuration in Tailwind v4.0. You’ll be able to specify exactly what you want directly in your HTML file without extra configuration.
In Tailwind v3, you’d need to define the number of columns in your tailwind.config.js
file, but in Tailwind v4.0 you can use any number from as small as grid-cols-5
to as large as grid-cols-73
. It also applies to the z-index utilities (for example, z-40
) and opacity-*
.
Tailwind v4.0 also has built-in support for variants like data-*
. You can use them without arbitrary values.
The main benefit of these changes is that developers will be able to spend less time configuring non-essential, or non-core, design tokens.
Dynamic spacing scale
Spacing utilities, like m-*
, w-*
, mt-*
, px-*
, and more, are generated dynamically using a base spacing value of 0.25rem
defined in the default Tailwind v4.0 theme.
Every multiple of the base spacing value is available in the spacing scale. So if mt-1
is 0.25rem
, mt-2
will be 0.25rem
multiplied by two, which is 0.5rem
, and mt-21
will be 5.25rem
:
You can use spacing utilities with values that aren’t explicitly defined. In Tailwind v3, you’d need to use an arbitrary value like mt-[5.25rem]
or a custom theme. There’s no need for additional configuration and you can create more consistent designs.
If you want to limit the available spacing values, you can disable the default variable and define a custom scale:
@theme {
--spacing: initial
--spacing-1: 0.25rem
--spacing-2: 0.5rem
--spacing-4: 1rem
--spacing-8: 2rem
--spacing-12: 3rem
}
With this setup, every Tailwind spacing utility will only use the specifically defined values.
Updated color palette
Tailwind v4 is moving from the default rgb
color palette to oklch
, which enables more vibrant colors, and is less limited than rgb
:
Container query support
Container queries now have built-in support in Tailwind CSS v4.0; you won’t need the @tailwindcss/container-queries
plugin to create responsive containers.
Container queries are used to apply styling to an element based on the size of its parent container. This means your site’s layout adapts to individual components rather than the entire viewport.
In v4.0, you create container queries by adding the @container
utility to a parent element. For the child elements, you use responsive utilities like @sm
and @lg
to apply styling based on the parent’s size:
<div className="@container">
<header className="flex justify-between @sm:grid-cols-2 @lg:grid-cols-4">
<!-- child content -->
</header>
</div>
Tailwind v4.0 also introduces a new @max-*
variant for max-width container queries. It makes it easier to add styling when the container goes below a certain size. You can combine @min-*
and @max-*
to define container query ranges:
<div className="@container">
<div className="flex @min-md:@max-xl:hidden">
<!-- child content -->
</div>
</div>
In this code, the child div
will be hidden when the width of the parent container is between md
and xl
(768px
and 1280px
).
Use cases for container queries include navigation, sidebars, cards, image galleries, and responsive text. They also provide more flexibility and are well-supported across browsers, so you can start using them in your v4.0 projects.
Migrating from v3 to Tailwind CSS v4.0
If you want to upgrade a v3 project to v4, Tailwind has provided an upgrade tool to do most of the work for you.
To upgrade your project, run the following command:
npx @tailwindcss/upgrade@next
The upgrade tool will automate several tasks like updating dependencies, migrating your JS config file to CSS, and handling changes in your template files.
Tailwind recommends using a new branch for the upgrade, to keep your main branch intact, and carefully reviewing the diff. Running a git diff
command helps you see and understand the changes in your project. You’d also want to test your project in a browser to confirm everything is working as it should.
Complex projects might require you to make manual adjustments, and Tailwind has outlined key changes and how to adapt to them, which we’ll cover below.
Dependency changes
PostCSS plugin: In v4.0, the PostCSS plugin is now available as a dedicated package, @tailwindcss/postcss
. You can remove postcss-import
and auto-prefixer
from the postcss.config.mjs
file in your existing project:
export default {
plugins: {
'@tailwindcss/postcss': {},
},
};
If you are starting a new project, you can now install Tailwind alongside the PostCSS plugin by running the following command:
npm install tailwindcss@next @tailwindcss/postcss@next
Vite plugin: Tailwind CSS v4.0 also has a new dedicated Vite plugin, which they recommend you migrate to from the PostCSS plugin:
import { defineConfig } from 'vite';
import tailwindcss from '@tailwindcss/vite';
export default defineConfig({
plugins: [
tailwindcss()
],
});
As we’ve seen with PostCSS, you can install v4.0 along with the Vite plugin when setting up a new project:
npm install tailwindcss@next @tailwindcss/vite@next
Tailwind CLI: Using the CLI tool is the easiest and fastest way to set up Tailwind CSS, and it now resides in a dedicated @tailwind/cli
package.
You’d need to update your build commands accordingly:
npx @tailwindcss/cli -i input.css -o output.css
Deprecated utilities
Several outdated or undocumented utilities have been removed and replaced with modern alternatives:
Configuring the container
utility
In v4.0, you configure the container
utility with @utility
:
@import "tailwindcss";
@utility container {
margin-inline: auto;
padding-inline: 2rem;
}
Configuration options like center
and padding
don’t exist in v4.0.
Default scale changes
Default scale adjustments have been made to every shadow, blur, and border-radius utility, to make sure they have a named value:
You’d need to replace each utility in your project to ensure things don’t look different.
Default border color change
In v3, the default border color is gray-200
. You didn’t need to explicitly set a color when using the border
utility:
<header className="flex justify-between border-b-2 py-4 px-8">
<--! content -->
</header>
In Tailwind CSS v4, the border color is updated to currentColor
, and your current project may experience a visual change if you don’t specify a color anywhere you use the border
utility.
Here’s the default border color in v4.0:
To maintain the v3 default behavior, you can add these CSS lines to your project:
the v3 behavior:
@import "tailwindcss";
@layer base {
*,
::after,
::before,
::backdrop,
::file-selector-button {
border-color: var(--color-gray-200, currentColor);
}
}
Default ring
width change
The ring
utility adds a 3px ring in v3, but it defaults to 1px in v4. Replace any usage of the ring
utility with ring-3
when updating your project to maintain its appearance.
Default placeholder change
In v4, placeholder text will use the current text color at 50% opacity by default. It uses the gray-400
color in v3, and if you want to preserve this behavior, add this to your CSS:
@layer base {
input::placeholder,
textarea::placeholder {
color: theme(--color-gray-400);
}
}
Outline changes
Also in v4, the outline-none
utility doesn’t add a transparent 2px
outline like it does in v3. There’s a new outline-hidden
utility in v4 that behaves like outline-none
from v3.
When upgrading your project, you’d need to replace outline-none
with outline-hidden
to maintain its current state, except you want to remove the outline entirely.
Adding custom utilities
Custom utilities now work with the new @utility
API instead of @layer
utility. This change ensures compatibility with native cascade layers.
tThey are now just single-class names and no longer complex selectors:
@utility tab-4 {
tab-size: 4;
}
Stacking order-sensitive variants
Tailwind v4.0 stacks variants like first
and last
from left to right, so you will need to order the variants in your project.
CSS variables in arbitrary values
The syntax for variables in arbitrary values has changed from square brackets to parenthesis to avoid ambiguity with new CSS standards. You’d need to update this in your project:
<div class="bg-(--brand-color)">
<!-- ... -->
</div>
Hover styles on mobile
In v4, hover styles will only work on devices that support hover interactions to align with accessibility practices.
You can enable backward compatibility by defining a hover
variant in the CSS file:
@import "tailwindcss";
@variant hover (&:hover);
Using the theme()
function
Tailwind CSS v4.0 generates variables for all theme values so the theme()
function is not necessary. Tailwind recommends that all theme()
functions in your project be replaced with CSS variables wherever possible:
@import "tailwindcss";
.my-class {
background-color: var(--color-red-500);
}
For more details about the changes coming in Tailwind v4.0, you should visit the prerelease documentation.
Tailwind and alternative CSS frameworks
The most obvious alternative to Tailwind CSS is Bootstrap, the most popular CSS framework in the world. It has an extensive library of predefined components.
Bootstrap is perhaps more beginner-friendly than Tailwind CSS. You can create ready-to-use components using specific and straightforward class names. Tailwind requires you to understand the utilities and their underlying CSS rules.
Another advantage Bootstrap has over Tailwind CSS is that it includes JavaScript by default, so you can do more backend stuff. Tailwind CSS has to be combined with JS frameworks.
However, Bootstrap is not as customizable or as flexible as Tailwind CSS. A long-standing argument is that all Bootstrap sites look the same. With its utility-first approach, Tailwind offers more flexibility and control.
Tailwind CSS cons
More utility-first CSS frameworks have popped up in recent years, like missing.css and Mojo CSS. None have been able to take the crown from Tailwind, but that’s not to say it’s not without its fair share of limitations:
Steep learning curve: As earlier mentioned, the utility-first approach and large number of classes can be difficult for beginners to learn.
Code readability: Because you’re working mainly in your HTML file, the code can become hard to read as each element accumulates utilities.
Inconsistent design: The flexibility of Tailwind CSS can lead to inconsistent designs across a project if you’re not mindful.
Switching frameworks: Projects can become tightly coupled with Tailwind CSS, making it difficult to switch to another framework.
Transitioning to Tailwind CSS v4.0
Upgrading your existing projects to the new version of Tailwind may seem like a difficult task, and this is true if you have a complex project, but the benefits are worthwhile. Tailwind is making everything faster and simpler by removing additional tools and files and providing clearer syntax.
The post Getting ready for Tailwind v4.0 appeared first on LogRocket Blog.