File: tailwindcss-v4-alpha.md | Updated: 11/15/2025
βKCtrlΒ KDocs Blog Showcase Sponsor Plus
March 6, 2024

Adam Wathan

Last summer at Tailwind Connect I shared a preview of Oxide β a new high-performance engine for Tailwind CSS that we've been working on, designed to simplify the developer experience and take advantage of how the web platform has evolved in recent years.
The new engine was originally going to ship as a v3.x release, but even though we're committed to backwards compatibility, this feels so clearly like a new generation of the framework that it deserves to be v4.0.
It's still early and we've got a lot of work to do , but today we're open-sourcing our progress and tagging the first public v4.0.0-alpha so you can start experimenting with it and help us get to a stable release later this year.
I'll try keep it brief to save some of the excitement for the stable release, but if you like to play with very early and experimental stuff, there should be plenty of information here to get you going.
The new engine is a ground-up rewrite, using everything we know about the framework now to better model the problem space, making things faster with a lot less code.
Tailwind CSS v4 isn't just a plugin anymore β it's an all-in-one tool for processing your CSS. We've integrated Lightning CSS directly into the framework so you don't have to configure anything about your CSS pipeline.
@import handling β no need to setup and configure a tool like postcss-import.autoprefixer to your projects anymore.oklch() colors and media query ranges are transpiled to syntax with better browser support.We're still shipping a PostCSS plugin, but we're also exploring first-party bundler plugins, and we're shipping an official Vite plugin with this first alpha release that you can try out today.
We're looking into the future with Tailwind CSS v4 and trying to build a framework that's going to feel cutting edge for years to come.
@layer rules now, which solves a ton of specificity problems we've wrestled with in the past.@property to define our internal custom properties with proper types and constraints, making it possible to do things like transition background gradients.color-mix for opacity modifiers β making it easier than ever to use our opacity modifier syntax when using CSS variables for colors, or even adjusting the opacity of currentColor.@min-* and @max-* variants to support container query ranges.We're also working on refreshing our color palette with wide gamut colors, and introducing support for other modern CSS features like @starting-style, anchor positioning, and more.
The new architecture makes it possible to compose together variants that act on other selectors, like group-*, peer-*, has-*, and a new not-* variant we're introducing for v4.
In earlier releases, variants like group-has-* were explicitly defined in the framework, but now group-* can compose with the existing has-* variant, which can compose with other variants like focus:
index.html
<div class="group"> <div class="group-has-[&:focus]:opacity-100"> <div class="group-has-focus:opacity-100"> <!-- ... --> </div> </div></div>
There's no limits to this composability, and you can even write stuff like group-not-has-peer-not-data-active:underline if for some horrible reason that's what you need to do.
Zero-configuration content detection
You'll notice that at least in these early alpha releases, it's not even possible to configure your content paths. For most projects, you're never going to need to do this ever again β Tailwind just finds your template files for you.
We do this using one of two ways depending on how you've integrated Tailwind into your project:
Using the PostCSS plugin or the CLI, Tailwind will crawl your entire project looking for template files, using a bunch of heuristics we've built in to keep things fast, like not crawling directories that are in your .gitignore file, and ignoring binary file formats.
Using the Vite plugin, we rely on the module graph. This is amazing because we know exactly what files you're actually using, so it's maximally performant, and with no false positives or negatives. We're hoping to expand this approach outside of the Vite ecosystem with other bundler plugins in the future.
We'll introduce a way to configure content paths explicitly in the future for sure, but we're curious to see how well this automatic approach works for everyone β it's working awesome in our own projects.
A major goal of Tailwind CSS v4.0 is making the framework feel CSS-native, and less like a JavaScript library.
Once you've installed it, you add it to your project with a regular CSS @import statement:
main.css
@import "tailwindcss";
And instead of setting up all of your customizations in a JavaScript configuration file, you just use CSS variables:
main.css
@import "tailwindcss";@theme { --font-family-display: "Satoshi", "sans-serif"; --breakpoint-3xl: 1920px; --color-neon-pink: oklch(71.7% 0.25 360); --color-neon-lime: oklch(91.5% 0.258 129); --color-neon-cyan: oklch(91.3% 0.139 195.8);}
The special @theme directive tells Tailwind to make new utilities and variants available based on those variables, letting you use classes like 3xl:text-neon-lime in your markup:
index.html
<div class="max-w-lg 3xl:max-w-xl"> <h1 class="font-display text-4xl"> Data to <span class="text-neon-cyan">enrich</span> your online business </h1></div>
Adding new CSS variables behaves like extend did in earlier versions of the framework, but you can override a whole set of variables by clearing the namespace with syntax like --color-*: initial before defining all of your custom values:
main.css
@import "tailwindcss";@theme { --color-*: initial; --color-gray-50: #f8fafc; --color-gray-100: #f1f5f9; --color-gray-200: #e2e8f0; /* ... */ --color-green-800: #3f6212; --color-green-900: #365314; --color-green-950: #1a2e05;}
We're still fine-tuning some of the naming conventions, but you can explore the default theme on GitHub to see what's available to customize.
If you don't want to explicitly clear the default theme and would rather start from scratch, you can import "tailwindcss/preflight" and "tailwindcss/utilities" directly to skip importing the default theme:
main.css
@import "tailwindcss";@import "tailwindcss/preflight" layer(base);@import "tailwindcss/utilities" layer(utilities);@theme { --color-*: initial; --color-gray-50: #f8fafc; --color-gray-100: #f1f5f9; --color-gray-200: #e2e8f0; /* ... */ --color-green-800: #3f6212; --color-green-900: #365314; --color-green-950: #1a2e05;}
We also make all of your theme values available as native CSS variables in your custom CSS:
dist/main.css
:root { --color-gray-50: #f8fafc; --color-gray-100: #f1f5f9; --color-gray-200: #e2e8f0; /* ... */ --color-green-800: #3f6212; --color-green-900: #365314; --color-green-950: #1a2e05;}
This makes it easy to reference any of your theme values in arbitrary values without needing the theme() function:
index.html
<div class="p-[calc(var(--spacing-6)-1px)]"> <!-- ... --></div>
It also makes it possible to use your theme values when working with UI libraries like Framer Motion, without having to use the resolveConfig() function:
JSX
import { motion } from "framer-motion";export const MyComponent = () => ( <motion.div initial={{ y: "var(--spacing-8)" }} animate={{ y: 0 }} exit={{ y: "var(--spacing-8)" }}> {children} </motion.div>);
We don't take breaking changes lightly, but there are a few things we're doing differently in v4 so far that are worth sharing:
text-opacity-*, flex-grow-*, and decoration-slice in favor of their modern replacements like text-{color}/*, grow-*, and box-decoration-slice.tailwindcss package doesn't include these anymore since not everyone needs them, instead they should be installed separately using @tailwindcss/postcss and @tailwindcss/cli.border utility used to default to gray-200, but now it defaults to currentColor like the browser does. We made this change to make it harder to accidentally introduce a wrong gray into your project if you're using zinc or slate or something else as your main gray.ring utility used to be a 3px blue ring by default, now it's a 1px ring using currentColor. We find ourselves using the ring-* utilities as an alternative to borders in our projects, and using outline-* for focus rings, so we think making things consistent here is a helpful change.There are a handful of other really low-level implementation detail changes that might surface in some way in your projects, but nothing deliberate like these changes. If you bump into anything surprising, let us know.
This new engine is a ground-up rewrite, and up until now we've been focused entirely on this reimagined developer experience using the new configuration approach.
We put an enormous amount of value in backwards compatibility, and that's where the bulk of the work lies before we can tag a stable v4.0 release later this year.
tailwind.config.js file to make migrating to v4 easy.important configuration β there's no way to make utilities all generate with !important right now, but we plan to implement it.theme() function β this isn't needed for new projects because you can use var() now, but we'll implement it for backwards compatibility.Aside from that, I'm sure we'll find a lot of bugs to fix, some exciting new CSS features to sneak in, and refine some of these new APIs that need some more polish before a proper release.
I don't want to make promises on a specific release timeline, but I'd personally love to mark v4.0 as stable before the summer holiday season kicks in.
We've tagged a couple alpha releases already, and you can start playing with it in your projects today.
If you're using the Tailwind CSS IntelliSense extension for VS Code, make sure you switch to the prerelease version from the extension page, and if you're using our Prettier plugin, make sure you install the latest version.
If you find an issue, please let us know on GitHub . We really want this thing to be bullet-proof before we tag a stable release and reporting any problems you find will help us a lot.
Install the Tailwind CSS v4 alpha and our new Vite plugin:
npm install tailwindcss@next @tailwindcss/vite@next
Then add our plugin to your vite.config.ts file:
vite.config.ts
import tailwindcss from "@tailwindcss/vite";import { defineConfig } from "vite";export default defineConfig({ plugins: [tailwindcss()],});
Finally, import Tailwind in your main CSS file:
app.css
@import "tailwindcss";
Install the Tailwind CSS v4 alpha and the separate PostCSS plugin package:
npm install tailwindcss@next @tailwindcss/postcss@next
Then add our plugin to your postcss.config.js file:
postcss.config.js
module.exports = { plugins: { "@tailwindcss/postcss": {}, },};
Finally, import Tailwind in your main CSS file:
app.css
@import "tailwindcss";
Install the Tailwind CSS v4 alpha and the separate CLI package:
npm install tailwindcss@next @tailwindcss/cli@next
Next, import Tailwind in your main CSS file:
app.css
@import "tailwindcss";
Finally, compile your CSS using the CLI tool:
npx @tailwindcss/cli@next -i app.css -o dist/app.css
Subscribe
Copyright © 2025 Tailwind Labs Inc.·Trademark Policy