|
| 1 | +--- |
| 2 | +name: tailwind-impl-build-vite |
| 3 | +description: > |
| 4 | + Use when wiring Tailwind CSS into a Vite project: choosing between the |
| 5 | + v4 dedicated Vite plugin and the v3 PostCSS pipeline, picking the right |
| 6 | + packages and configs, importing the stylesheet, enabling HMR, and |
| 7 | + scoping template-scan paths in monorepos. Prevents the wrong-plugin |
| 8 | + trap (using postcss-plugin with v4 instead of @tailwindcss/vite gives |
| 9 | + much slower builds and broken at-rules), the broken-classnames trap |
| 10 | + (writing @import "tailwindcss" in v3 yields no utilities), the |
| 11 | + missing-content trap (v3 without content paths produces an empty |
| 12 | + stylesheet), the missing-source trap (v4 in a monorepo where workspace |
| 13 | + templates live outside the Vite root never get scanned), the upgrade |
| 14 | + trap (v4-0-8 Astro break, issue 16733), and the wrong-tool trap |
| 15 | + (chasing Turbopack issue 19825 in a Vite project). Covers v4 with |
| 16 | + @tailwindcss/vite (install, vite-config-ts plugin entry, @import |
| 17 | + "tailwindcss" in the entry CSS, automatic content detection, |
| 18 | + @source for monorepo/external paths, HMR), v3 with postcss-plugin |
| 19 | + (npm install -D tailwindcss postcss autoprefixer, npx tailwindcss |
| 20 | + init -p, postcss-config-js, tailwind-config-js content paths, the |
| 21 | + three @tailwind directives), framework-flavored Vite setups (React, |
| 22 | + Vue, Svelte, SolidJS, Astro, Qwik), library-mode and SSR notes, |
| 23 | + workspace and pnpm monorepo wiring, the v4-0-8 Astro regression |
| 24 | + workaround, and verifying that classnames actually generate CSS. |
| 25 | + Keywords: tailwind vite, @tailwindcss/vite, vite plugin tailwind, |
| 26 | + tailwind vite install, tailwind v4 vite, tailwind v3 vite, |
| 27 | + postcss tailwind vite, vite-config-ts plugin order, @import tailwindcss, |
| 28 | + @tailwind base components utilities, npx tailwindcss init -p, |
| 29 | + tailwind init vite, tailwind.config.js content paths, HMR tailwind, |
| 30 | + hot reload tailwind vite, monorepo tailwind vite, pnpm workspace |
| 31 | + tailwind, @source workspace, tailwind v4 monorepo, library mode |
| 32 | + tailwind, vite ssr tailwind, astro tailwind v4 broken, tailwind |
| 33 | + v4-0-8 break, classes not applying vite, no styles vite tailwind, |
| 34 | + empty stylesheet vite tailwind, where is tailwind.config v4, |
| 35 | + how to install tailwind in vite, getting started tailwind vite, |
| 36 | + styles missing after build, blank styles vite, vite plugin order |
| 37 | + tailwind, react vite tailwind, vue vite tailwind, svelte vite |
| 38 | + tailwind, solidjs vite tailwind, qwik vite tailwind, why nothing |
| 39 | + shows tailwind, my classes are not working tailwind vite. |
| 40 | +license: MIT |
| 41 | +compatibility: "Designed for Claude Code. Requires Tailwind CSS v3.4 or v4.0+." |
| 42 | +metadata: |
| 43 | + author: OpenAEC-Foundation |
| 44 | + version: "1.0" |
| 45 | +--- |
| 46 | + |
| 47 | +# Tailwind CSS Build Integration with Vite |
| 48 | + |
| 49 | +Vite has two completely separate Tailwind integration paths: |
| 50 | + |
| 51 | +- **v4** : the dedicated `@tailwindcss/vite` plugin (preferred for v4) |
| 52 | +- **v3** : the legacy `tailwindcss` PostCSS plugin (used via Vite's built-in PostCSS) |
| 53 | + |
| 54 | +ALWAYS match plugin to version. NEVER use `@tailwindcss/postcss` with v4 inside |
| 55 | +Vite when `@tailwindcss/vite` is available : the dedicated plugin is faster, |
| 56 | +supports the v4 at-rules natively, and integrates with Vite's HMR and |
| 57 | +dependency graph. |
| 58 | + |
| 59 | +Companion skills : |
| 60 | + |
| 61 | +- `tailwind-impl-config-v3` : the v3 JS-config surface |
| 62 | +- `tailwind-impl-config-v4` : the v4 CSS-first config surface |
| 63 | +- `tailwind-core-v3-vs-v4` : behavioral differences between versions |
| 64 | + |
| 65 | +## Quick Reference |
| 66 | + |
| 67 | +### v4 with @tailwindcss/vite (preferred) |
| 68 | + |
| 69 | +Install : |
| 70 | + |
| 71 | +```bash |
| 72 | +npm install tailwindcss @tailwindcss/vite |
| 73 | +``` |
| 74 | + |
| 75 | +`vite.config.ts` : |
| 76 | + |
| 77 | +```ts |
| 78 | +import { defineConfig } from "vite" |
| 79 | +import tailwindcss from "@tailwindcss/vite" |
| 80 | + |
| 81 | +export default defineConfig({ |
| 82 | + plugins: [ |
| 83 | + tailwindcss(), |
| 84 | + ], |
| 85 | +}) |
| 86 | +``` |
| 87 | + |
| 88 | +`src/style.css` (entry stylesheet) : |
| 89 | + |
| 90 | +```css |
| 91 | +@import "tailwindcss"; |
| 92 | +``` |
| 93 | + |
| 94 | +Reference the entry stylesheet from your HTML or framework entry |
| 95 | +(`<link rel="stylesheet" href="/src/style.css">` for vanilla, `import |
| 96 | +"./style.css"` from `main.ts` for React/Vue/Svelte/SolidJS). |
| 97 | + |
| 98 | +No `tailwind.config.js` is required. v4 auto-detects template files |
| 99 | +relative to the Vite root via `.gitignore` and source-scanner heuristics. |
| 100 | + |
| 101 | +### v3 with PostCSS |
| 102 | + |
| 103 | +Install : |
| 104 | + |
| 105 | +```bash |
| 106 | +npm install -D tailwindcss@3 postcss autoprefixer |
| 107 | +npx tailwindcss init -p |
| 108 | +``` |
| 109 | + |
| 110 | +The `-p` flag also generates `postcss.config.js`. Vite reads it automatically. |
| 111 | + |
| 112 | +`tailwind.config.js` : |
| 113 | + |
| 114 | +```js |
| 115 | +/** @type {import('tailwindcss').Config} */ |
| 116 | +export default { |
| 117 | + content: [ |
| 118 | + "./index.html", |
| 119 | + "./src/**/*.{js,ts,jsx,tsx,vue,svelte}", |
| 120 | + ], |
| 121 | + theme: { |
| 122 | + extend: {}, |
| 123 | + }, |
| 124 | + plugins: [], |
| 125 | +} |
| 126 | +``` |
| 127 | + |
| 128 | +`postcss.config.js` (generated by `init -p`) : |
| 129 | + |
| 130 | +```js |
| 131 | +export default { |
| 132 | + plugins: { |
| 133 | + tailwindcss: {}, |
| 134 | + autoprefixer: {}, |
| 135 | + }, |
| 136 | +} |
| 137 | +``` |
| 138 | + |
| 139 | +`src/index.css` : |
| 140 | + |
| 141 | +```css |
| 142 | +@tailwind base; |
| 143 | +@tailwind components; |
| 144 | +@tailwind utilities; |
| 145 | +``` |
| 146 | + |
| 147 | +ALWAYS list every template extension you actually use in `content`. |
| 148 | +Anything not matched is invisible to the JIT scanner and produces no CSS. |
| 149 | + |
| 150 | +## Decision Trees |
| 151 | + |
| 152 | +### Which plugin should I use ? |
| 153 | + |
| 154 | +``` |
| 155 | +Tailwind major version ? |
| 156 | +├── v4 (4.0.0 and above) |
| 157 | +│ └── ALWAYS @tailwindcss/vite |
| 158 | +│ NEVER @tailwindcss/postcss in a Vite project |
| 159 | +│ NEVER the v3 tailwindcss postcss-plugin (it will not parse v4 at-rules) |
| 160 | +└── v3 (3.x) |
| 161 | + └── ALWAYS the tailwindcss postcss-plugin via postcss.config.js |
| 162 | + NEVER @tailwindcss/vite (it only exists for v4) |
| 163 | +``` |
| 164 | + |
| 165 | +### What entry CSS should I write ? |
| 166 | + |
| 167 | +``` |
| 168 | +Version ? |
| 169 | +├── v4 : @import "tailwindcss"; |
| 170 | +│ (single line, no @tailwind directives) |
| 171 | +└── v3 : @tailwind base; |
| 172 | + @tailwind components; |
| 173 | + @tailwind utilities; |
| 174 | + (all three required, in this order) |
| 175 | +``` |
| 176 | + |
| 177 | +### My classes are not applying. Where do I look ? |
| 178 | + |
| 179 | +``` |
| 180 | +1. Is the entry CSS imported into the app entry ? |
| 181 | + ├── No : add import "./style.css" in main.ts (or <link> in index.html) |
| 182 | + └── Yes : continue |
| 183 | +2. Is the Tailwind plugin registered in vite.config.ts (v4) or |
| 184 | + postcss.config.js (v3) ? |
| 185 | + ├── No : add it |
| 186 | + └── Yes : continue |
| 187 | +3. v3 : does tailwind.config.js content include the files you write classes in ? |
| 188 | + ├── No : add the glob (e.g. "./src/**/*.{ts,tsx}") |
| 189 | + └── Yes : continue |
| 190 | +4. v4 : are the files inside the Vite root, and not gitignored ? |
| 191 | + ├── Outside root or gitignored : add @source "path"; in your entry CSS |
| 192 | + └── Yes : continue |
| 193 | +5. Are class names produced by string concatenation |
| 194 | + (e.g. "text-" + color) ? |
| 195 | + └── Yes : the JIT scanner cannot see them, use safelist |
| 196 | + (v3 safelist in config, v4 @source inline "{...}" brace expansion) |
| 197 | +6. Inspect the built CSS in DevTools : if utilities are missing, |
| 198 | + the scanner did not see your file. If present but not applied, |
| 199 | + it is a specificity or order issue, not a Tailwind setup issue. |
| 200 | +``` |
| 201 | + |
| 202 | +### Monorepo : how do I include workspace packages ? |
| 203 | + |
| 204 | +``` |
| 205 | +Version ? |
| 206 | +├── v3 : extend content paths in tailwind.config.js : |
| 207 | +│ content: [ |
| 208 | +│ "./index.html", |
| 209 | +│ "./src/**/*.{ts,tsx,vue,svelte}", |
| 210 | +│ "../../packages/ui/src/**/*.{ts,tsx}", |
| 211 | +│ ], |
| 212 | +└── v4 : add @source entries to the entry CSS : |
| 213 | + @import "tailwindcss"; |
| 214 | + @source "../../packages/ui/src/**/*.{ts,tsx}"; |
| 215 | + (the v4 plugin auto-detects files only within the Vite root |
| 216 | + and respects .gitignore, so external packages need @source) |
| 217 | +``` |
| 218 | + |
| 219 | +## Patterns |
| 220 | + |
| 221 | +### Pattern : framework-flavored Vite setup (v4) |
| 222 | + |
| 223 | +For React (`@vitejs/plugin-react`), Vue (`@vitejs/plugin-vue`), Svelte |
| 224 | +(`@sveltejs/vite-plugin-svelte`), SolidJS (`vite-plugin-solid`), or Qwik : |
| 225 | +add `tailwindcss()` to the `plugins` array. Order does not matter for |
| 226 | +Tailwind's CSS pipeline, but ALWAYS keep the framework plugin first |
| 227 | +when a framework provides its own CSS preprocessor (Svelte, Vue) so |
| 228 | +component-scoped styles are parsed before Tailwind sees them. |
| 229 | + |
| 230 | +```ts |
| 231 | +import { defineConfig } from "vite" |
| 232 | +import react from "@vitejs/plugin-react" |
| 233 | +import tailwindcss from "@tailwindcss/vite" |
| 234 | + |
| 235 | +export default defineConfig({ |
| 236 | + plugins: [ |
| 237 | + react(), |
| 238 | + tailwindcss(), |
| 239 | + ], |
| 240 | +}) |
| 241 | +``` |
| 242 | + |
| 243 | +### Pattern : single-file CSS for v3 vs v4 |
| 244 | + |
| 245 | +v4 entry CSS : |
| 246 | + |
| 247 | +```css |
| 248 | +@import "tailwindcss"; |
| 249 | + |
| 250 | +@theme { |
| 251 | + --color-brand: oklch(0.7 0.2 145); |
| 252 | +} |
| 253 | +``` |
| 254 | + |
| 255 | +v3 entry CSS : |
| 256 | + |
| 257 | +```css |
| 258 | +@tailwind base; |
| 259 | +@tailwind components; |
| 260 | +@tailwind utilities; |
| 261 | + |
| 262 | +@layer base { |
| 263 | + :root { |
| 264 | + --brand: 220 90% 56%; |
| 265 | + } |
| 266 | +} |
| 267 | +``` |
| 268 | + |
| 269 | +NEVER mix the two : the three v3 directives are silently ignored by v4, |
| 270 | +and `@import "tailwindcss"` is meaningless in v3. |
| 271 | + |
| 272 | +### Pattern : HMR for design tokens |
| 273 | + |
| 274 | +HMR works out of the box in both versions. Editing the entry CSS, |
| 275 | +`tailwind.config.js` (v3), or any file matched by content/`@source` |
| 276 | +triggers a stylesheet swap with no full reload. ALWAYS rely on this : |
| 277 | +NEVER write a custom Vite plugin to watch Tailwind files. |
| 278 | + |
| 279 | +If HMR appears broken, the cause is almost always one of : |
| 280 | + |
| 281 | +1. The file you edited is not in `content` (v3) or not in the Vite root |
| 282 | + without an `@source` entry (v4). |
| 283 | +2. A separate dev server proxy strips Vite's WebSocket connection. |
| 284 | +3. The browser cached the old stylesheet : hard-reload once. |
| 285 | + |
| 286 | +### Pattern : library-mode and SSR |
| 287 | + |
| 288 | +In `build.lib` mode, the Tailwind plugin still runs and emits the |
| 289 | +generated stylesheet alongside your library bundle. ALWAYS export the |
| 290 | +stylesheet path so consumers can import it. For SSR (`vite-node`, SvelteKit, |
| 291 | +Astro, Nuxt), the plugin runs once per build : no extra setup is needed |
| 292 | +beyond standard SSR-safe usage of the generated CSS. |
| 293 | + |
| 294 | +## Anti-Patterns |
| 295 | + |
| 296 | +NEVER install both `@tailwindcss/vite` and `@tailwindcss/postcss` in |
| 297 | +the same Vite project. They both transform CSS and double-process at-rules. |
| 298 | + |
| 299 | +NEVER add `@tailwind base/components/utilities` to a v4 entry stylesheet. |
| 300 | +v4 ignores those directives. The single `@import "tailwindcss"` replaces all three. |
| 301 | + |
| 302 | +NEVER write `@import "tailwindcss"` in a v3 entry. v3 has no such import |
| 303 | +target and will leave the line unresolved, producing zero utilities. |
| 304 | + |
| 305 | +NEVER configure `content` in `tailwind.config.js` when using v4 with |
| 306 | +`@tailwindcss/vite`. The v4 scanner ignores the JS config unless you |
| 307 | +opt in via `@config`. Use `@source` directives in CSS instead. |
| 308 | + |
| 309 | +NEVER set `optimizeDeps.exclude: ["tailwindcss"]` in `vite.config.ts`. |
| 310 | +It is a runtime non-issue and only slows the first dev start. |
| 311 | + |
| 312 | +See `references/anti-patterns.md` for the full catalog with quoted |
| 313 | +error symptoms and fixes. |
| 314 | + |
| 315 | +## Common Breakage |
| 316 | + |
| 317 | +### v4.0.8 Astro regression (tailwindlabs/tailwindcss#16733) |
| 318 | + |
| 319 | +Tailwind v4.0.8 + Astro + `@tailwindcss/vite` regressed parsing of |
| 320 | +component-package styles. Symptom : utilities that worked under 4.0.7 |
| 321 | +silently stopped applying after upgrade. |
| 322 | + |
| 323 | +ALWAYS pin to 4.0.7 OR upgrade past the patched release if you are on |
| 324 | +Astro + Vite and hit missing utilities right after a 4.0.8 bump : |
| 325 | + |
| 326 | +```json |
| 327 | +"dependencies": { |
| 328 | + "tailwindcss": "4.0.7", |
| 329 | + "@tailwindcss/vite": "4.0.7" |
| 330 | +} |
| 331 | +``` |
| 332 | + |
| 333 | +### Turbopack arbitrary-value miss (tailwindlabs/tailwindcss#19825) |
| 334 | + |
| 335 | +Issue 19825 reports arbitrary-value classes like `aspect-[12/5]`, |
| 336 | +`z-[100]`, `h-[80vh]` missing in Next.js + Turbopack builds. |
| 337 | + |
| 338 | +This bug is Turbopack-specific. Vite users are NOT affected. |
| 339 | +If you are on Vite and arbitrary-value classes go missing, the cause |
| 340 | +is almost always a missing `@source` (v4) or content path (v3), |
| 341 | +NEVER this Turbopack bug. |
| 342 | + |
| 343 | +## Verification |
| 344 | + |
| 345 | +After install, ALWAYS verify with a single class that exercises the JIT : |
| 346 | + |
| 347 | +```html |
| 348 | +<div class="text-3xl font-bold underline">Tailwind is wired</div> |
| 349 | +``` |
| 350 | + |
| 351 | +If the text becomes large, bold, and underlined in the dev server, |
| 352 | +the entire chain (plugin registered, entry CSS imported, scanner |
| 353 | +seeing your template) is working. |
| 354 | + |
| 355 | +For arbitrary values, also try : |
| 356 | + |
| 357 | +```html |
| 358 | +<div class="text-[#ff00aa] h-[42vh]">Arbitrary values</div> |
| 359 | +``` |
| 360 | + |
| 361 | +If arbitrary values fail but utility classes work, the JIT engine |
| 362 | +is running but content/source scope is wrong. |
| 363 | + |
| 364 | +## Reference Links |
| 365 | + |
| 366 | +- `references/methods.md` : exhaustive API of @tailwindcss/vite plugin |
| 367 | + options, v3 PostCSS options, init flags, package commands |
| 368 | +- `references/examples.md` : full project examples for React, Vue, Svelte, |
| 369 | + SolidJS, Astro, Qwik, both v3 and v4, plus monorepo and library-mode |
| 370 | +- `references/anti-patterns.md` : every known wiring mistake with the |
| 371 | + exact error or symptom, the cause, and the fix |
| 372 | + |
| 373 | +## Sources |
| 374 | + |
| 375 | +- v4 install for Vite : https://tailwindcss.com/docs/installation/using-vite |
| 376 | +- v3 install for Vite : https://v3.tailwindcss.com/docs/guides/vite |
| 377 | +- v4 directives reference : https://tailwindcss.com/docs/functions-and-directives |
| 378 | +- @tailwindcss/vite plugin : https://github.com/tailwindlabs/tailwindcss/tree/next/packages/%40tailwindcss-vite |
| 379 | +- v4.0.8 Astro regression : https://github.com/tailwindlabs/tailwindcss/issues/16733 |
| 380 | +- Turbopack arbitrary-value miss (NOT Vite) : https://github.com/tailwindlabs/tailwindcss/issues/19825 |
0 commit comments