Install & Setup
Tailwind v4 installs as a plugin and scans your files for class names. Setup is a few commands.
Install
npm install tailwindcss @tailwindcss/vite
Vite Setup
Add the plugin to vite.config.js:
import { defineConfig } from "vite";
import tailwindcss from "@tailwindcss/vite";
export default defineConfig({
plugins: [tailwindcss()],
});
Import Tailwind
Add one line to your CSS entry file:
@import "tailwindcss";
That is the whole setup in v4. No config file required.
Start Using It
<h1 class="text-3xl font-bold text-blue-600">Hello, Tailwind!</h1>
How Content Detection Works
Tailwind v4 scans your project for class names automatically — it looks at your source files and generates only the utilities you use. Class names must appear as complete strings:
<div class="bg-red-500">Works</div>
<div class="bg-{color}-500">Does not work</div>
Dynamic class names built by string concatenation are invisible to the scanner.
Safelisting Dynamic Classes
When you must build classes dynamically, map them to full strings:
const colors = {
danger: "bg-red-500",
success: "bg-green-500",
};
Now the complete class names exist in the source and get generated.
Framework Notes
- React / Vue / Svelte — Same Vite plugin; use
classNamein React. - Astro — Add
@tailwindcss/vitetoastro.config.mjs. - PostCSS — Use
@tailwindcss/postcssif you cannot use Vite.
Full example
A complete Vite + Tailwind v4 project — five files from package.json to the first styled page.
{
"name": "tailwind-starter",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"devDependencies": {
"tailwindcss": "^4.0.0",
"@tailwindcss/vite": "^4.0.0",
"vite": "^6.0.0"
}
}
import { defineConfig } from "vite";
import tailwindcss from "@tailwindcss/vite";
export default defineConfig({
plugins: [tailwindcss()],
});
@import "tailwindcss";
@theme {
--color-brand: oklch(0.72 0.17 150);
}
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Tailwind starter</title>
</head>
<body class="min-h-screen bg-gray-950 text-gray-100">
<main class="mx-auto flex max-w-xl flex-col gap-6 p-8">
<h1 class="text-3xl font-bold tracking-tight">Hello, Tailwind!</h1>
<p class="text-gray-400">Edit index.html and the page updates instantly.</p>
<button
class="w-fit rounded-lg bg-brand px-4 py-2 font-medium text-gray-950 transition-colors hover:opacity-90 focus:outline-none focus:ring-2 focus:ring-brand"
>
Get started
</button>
</main>
<script type="module" src="/src/main.js"></script>
</body>
</html>
import "./style.css";
console.log("Tailwind is ready.");
Best Practices
- Keep the CSS entry minimal — Import Tailwind, add a few tokens.
- Write complete class names — So the scanner sees them.
- Avoid a config file until you need it — v4 works without one.
- Let the build handle purging — Unused utilities are dropped automatically.
Common Mistakes
- Forgetting the
@import— No styles are generated. - Dynamic class names —
"text-" + sizeproduces nothing. - Mixing old v3 config blindly — v4 moved configuration into CSS.
- Adding the plugin after
build— Order can matter; follow the docs.