Tailwind v4 Not Working with Vite? The 3-Line Fix (and Why v3 Guides Break)
Tailwind CSS not working in Vite? v4 changed the setup: the @tailwindcss/vite plugin, one @import line, no init command. Tested fix, migration table, pitfalls.
If Tailwind isn’t working in your Vite project, you are almost certainly following a guide written for Tailwind v3 while npm install tailwindcss gives you v4. Version 4 changed the setup: install the @tailwindcss/vite plugin, add it to vite.config.ts, and replace the three @tailwind lines in your CSS with @import "tailwindcss";. There is no init command and no config file to create.
Everything here was tested on 26 October 2026 with Tailwind CSS 4.3.3 (and 3.4.19 for the v3 parts), Vite 8.3.5 from create-vite 9.3.1, React 19.3, Vue 3.5, Next.js 16.4.3 and Node.js 22.14.
Which symptom do you have?
Tailwind 4.0 came out in January 2025, so most tutorials and courses written before then fail in one of three ways:
| What you see | Why |
|---|---|
npx tailwindcss init -p prints npm error could not determine executable to run |
The v4 tailwindcss package has no command at all; the CLI moved to @tailwindcss/cli, which has no init either |
The build fails: It looks like you're trying to use tailwindcss directly as a PostCSS plugin |
A v3 postcss.config.js that lists tailwindcss as a plugin |
| The build succeeds, but the page has no Tailwind styles | The v3 @tailwind base; @tailwind components; @tailwind utilities; lines in your CSS |
The third one is the confusing one. With the v4 Vite plugin installed and the old @tailwind lines left in place, the build finishes without a single warning — and generates no utility classes at all. In testing, text-3xl and bg-sky-500 simply weren’t in the output CSS.
The fix: Vite with React, Vue, Svelte or plain JS
1. Install Tailwind and its Vite plugin:
npm install tailwindcss @tailwindcss/vite
2. Add the plugin to vite.config.ts, next to your framework’s plugin (vue(), svelte(), or none for plain JS):
import react from '@vitejs/plugin-react'
import tailwindcss from '@tailwindcss/vite'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [react(), tailwindcss()],
})
3. Replace everything Tailwind-related in your main CSS file with one line:
/* src/index.css */
@import "tailwindcss";
That CSS file must be imported by your entry file — import './index.css' in src/main.tsx (or ./style.css in src/main.ts for the Vue template), which create-vite already does. If you had a postcss.config.js from a v3 guide, delete it, and remove tailwind.config.js unless you want to keep using it (see below). Then restart npm run dev.
What changed from v3 to v4
| v3 habit | v4 equivalent |
|---|---|
npx tailwindcss init -p |
Nothing to run: no config file is needed |
@tailwind base; @tailwind components; @tailwind utilities; |
@import "tailwindcss"; |
theme.extend in tailwind.config.js |
An @theme { … } block in your CSS |
content: ["./src/**/*.{js,ts,jsx,tsx}"] |
Automatic detection; add other folders with @source |
postcss.config.js with tailwindcss and autoprefixer |
Vite: @tailwindcss/vite. Other PostCSS setups: @tailwindcss/postcss. No autoprefixer: prefixes are added for you (the build output contained -webkit-backdrop-filter without it) |
npx tailwindcss -i in.css -o out.css |
npx @tailwindcss/cli -i in.css -o out.css |
Some class names now mean something else
If you migrate by hand, watch for the utilities v4 renamed. Nothing errors, so the differences are easy to miss: the bare shadow, rounded and blur still work as before, but every -sm version now means what the bare one used to, so shadow-sm, rounded-sm and blur-sm look a step larger unless you change them to -xs:
| v3 | v4 |
|---|---|
shadow-sm |
shadow-xs |
shadow |
shadow-sm |
rounded-sm |
rounded-xs |
rounded |
rounded-sm |
blur-sm, backdrop-blur-sm |
blur-xs, backdrop-blur-xs |
outline-none |
outline-hidden |
ring |
ring-3 |
outline-none now really sets outline-style: none; the old behaviour, an invisible outline that still shows in forced-colours mode, is outline-hidden. Two defaults changed too: borders now use currentColor instead of gray-200, and ring is 1px instead of 3px. The upgrade tool handles all of this for you.
Customising the theme
Theme values are now CSS variables in an @theme block:
@import "tailwindcss";
@theme {
--color-brand: oklch(0.62 0.19 255);
--font-display: "Inter", sans-serif;
}
That gives you bg-brand, text-brand, font-display and the rest. The build turns the colour into a real variable, --color-brand, which you can also use in your own CSS.
Already have a tailwind.config.js that you don’t want to rewrite yet? Point the stylesheet at it; the path is relative to the CSS file:
@import "tailwindcss";
@config "../tailwind.config.js";
In testing, a v3-style config with theme.extend.colors.brand produced bg-brand this way.
Other reasons Tailwind classes don’t appear
The class is in a file Tailwind doesn’t scan
Tailwind v4 finds class names on its own, starting from the current working directory. It skips files listed in .gitignore, everything in node_modules, and anything outside that starting folder. In testing, all three cases produced no CSS, even though the app imported every one of those files:
- a component in a gitignored folder (generated code, for example),
- a UI library inside
node_modules, - a shared package in a sibling folder of a monorepo, such as
../shared-ui.
Register each one with @source, relative to the CSS file:
@import "tailwindcss";
@source "./generated"; /* a gitignored folder */
@source "../node_modules/fake-ui"; /* a package in node_modules */
@source "../../shared-ui/src"; /* a sibling package in a monorepo */
Use your own folder names. With those three lines, all the missing classes appeared. Because detection starts from the working directory, running the build from a different folder — a monorepo root, say — can also change what gets scanned.
@apply fails in a Vue <style> block or a CSS module
Vue and Svelte <style> blocks and CSS modules (*.module.css) are processed separately from your main stylesheet, so they don’t know about Tailwind’s classes. The build stops with:
Cannot apply unknown utility class `text-2xl`. Are you using CSS modules or similar and missing `@reference`?
Add @reference with the path to your main stylesheet. It makes the classes available to @apply without copying any of Tailwind’s CSS into the component:
<style scoped>
@reference "./style.css";
h1 {
@apply text-2xl font-bold;
}
</style>
The same line fixes a CSS module: @reference "./index.css"; at the top of Title.module.css. Both were tested; the Svelte case works the same way, according to Tailwind’s documentation.
The class name is built at runtime
Tailwind reads your source files as text; it never runs them. A class that only exists after string concatenation is never generated — this was already true in v3:
// ✗ Tailwind can't see this
<p className={`text-${color}-500`} />
// ✓ Use complete class names
const colors = { red: "text-red-500", blue: "text-blue-500" };
<p className={colors[color]} />
In testing, text-red-500 and text-blue-500 from the map were generated; text-green-500 and text-purple-500 from the template string were not.
The browser is too old
Tailwind v4 is designed for Safari 16.4+, Chrome 111+ and Firefox 128+. If you must support older browsers, Tailwind’s own advice is to stay on v3.4.
Autocomplete stopped working in the editor
The Tailwind CSS IntelliSense extension finds a v4 project through a CSS file that contains @import "tailwindcss", not through tailwind.config.js. Update the extension; if it still can’t find your stylesheet, point it there with the tailwindCSS.experimental.configFile setting, for example "tailwindCSS.experimental.configFile": "src/index.css".
Using Next.js instead of Vite?
Next.js uses PostCSS, so you install the PostCSS plugin instead of the Vite one:
npm install tailwindcss @tailwindcss/postcss
// postcss.config.mjs
export default { plugins: { "@tailwindcss/postcss": {} } };
/* app/globals.css */
@import "tailwindcss";
Import ./globals.css in app/layout.tsx. Tested with Next.js 16.4.3: the built CSS contained the utilities used in the layout.
Staying on v3
For an existing project you aren’t ready to migrate, or for older browsers, install v3 explicitly — then the old commands work again:
npm install -D tailwindcss@3 postcss autoprefixer
npx tailwindcss init -p
This installed 3.4.19 and created tailwind.config.js and postcss.config.js. Remember the step v3 guides include and v4 doesn’t need: list your files in content, for example ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"], or no classes are generated. For a new project, use v4: the setup is shorter, and it’s where Tailwind’s development happens.
Upgrading an existing v3 project
Tailwind ships an upgrade tool. It needs Node.js 20 or later; run it on a clean Git branch so you can review every change:
npx @tailwindcss/upgrade
On a v3 test project, it:
- moved
theme.extendfromtailwind.config.jsinto an@themeblock, and deleted the config file; - replaced the
@tailwindlines with@import 'tailwindcss';; - renamed classes in the components and in
@apply(backdrop-blur-smtobackdrop-blur-xs,shadowtoshadow-sm); - added a small
@layer baserule that keeps v3’s grey default border colour; - switched
postcss.config.jsto@tailwindcss/postcss, and removedautoprefixer.
The project built afterwards with the same classes in the output. The tool kept the PostCSS setup rather than switching to the Vite plugin; both work.
Checklist
- Check the installed version:
npm ls tailwindcss. - v4 with Vite:
@tailwindcss/viteinvite.config.ts, and@import "tailwindcss";in a CSS file your entry imports. - Delete the
@tailwindlines and any v3postcss.config.js; don’t runinit. - Put theme changes in
@theme, or point to an old config with@config. - Add
@sourcefor gitignored folders, packages innode_modulesand sibling packages. - Add
@referencebefore@applyin Vue or Svelte<style>blocks and CSS modules. - Write complete class names; never build them from strings.
- Migrating by hand? Check the renamed utilities (
shadow,rounded,blur,ring,outline-none). - Prefer
npx @tailwindcss/upgradeon a clean branch, then review the diff. - Need older browsers? Stay on
tailwindcss@3.
References and further reading
- Installing Tailwind CSS with Vite, Tailwind CSS documentation
- Upgrade guide, Tailwind CSS documentation
- Detecting classes in source files, Tailwind CSS documentation
- Functions and directives, Tailwind CSS documentation
- Tailwind CSS IntelliSense, Tailwind Labs, on GitHub