Integrating with frameworks and build tools
Wire Tailwind into Vite, PostCSS and the CLI, understand where @apply needs a reference, and set up the tooling that keeps class lists readable.
Vite and PostCSS
# Vite: the dedicated plugin is the fastest path
npm install tailwindcss @tailwindcss/vite// vite.config.ts
import { defineConfig } from "vite";
import tailwindcss from "@tailwindcss/vite";
export default defineConfig({
plugins: [tailwindcss()],
});/* src/app.css - the single entry point */
@import "tailwindcss";
/* components and utilities you own */
@layer components {
.card { @apply rounded-xl border border-slate-200 bg-white p-5; }
}// import the stylesheet once, at the application entry
import "./app.css";# PostCSS, for a build that is not Vite
npm install tailwindcss @tailwindcss/postcss postcss// postcss.config.mjs
export default {
plugins: {
"@tailwindcss/postcss": {},
},
};# the standalone CLI, for a static site with no bundler
npx @tailwindcss/cli -i ./src/app.css -o ./dist/app.css --watch --minifyOne entry point, one import. A second stylesheet that also imports Tailwind duplicates the preflight and the theme variables, which is how a page ends up with two conflicting resets.
@apply, @reference and layers
/* @apply works in the file that imports Tailwind */
@import "tailwindcss";
@layer components {
.btn {
@apply inline-flex items-center gap-2 rounded-md px-3.5 py-2 text-sm font-medium;
}
.btn-primary {
@apply bg-sky-600 text-white hover:bg-sky-500;
}
}<!-- a single-file component with a scoped style block -->
<style>
/* without this, @apply has no theme to resolve against */
@reference "../../app.css";
.prose-card {
@apply rounded-xl border p-6 text-slate-700;
}
.prose-card h2 {
@apply mt-0 text-xl font-semibold;
}
</style>| At-rule | Purpose |
|---|---|
@import "tailwindcss" | Loads the whole framework |
@theme | Declares design tokens |
@layer components | Registers your own component classes |
@utility | Registers a custom utility that works with variants |
@apply | Inlines utilities into a rule |
@reference | Gives a scoped style block access to the theme |
@variant | Applies a variant inside plain CSS |
⚠️
A component style block without
@reference fails with an unknown utility error, because that file has no theme of its own. It is the first thing to check when @apply stops working after a move to Vue, Svelte or Astro scoped styles.Tooling
# sort class lists automatically, so diffs are stable
npm install -D prettier-plugin-tailwindcss{
"plugins": ["prettier-plugin-tailwindcss"],
"tailwindStylesheet": "./src/app.css"
}- The Prettier plugin sorts classes into the framework's canonical order, which makes a diff show the real change instead of a reshuffle.
- Install the editor extension for autocomplete and hover previews; you cannot memorise the scale and there is no reason to.
- Add class sorting to the same pre-commit hook as the rest of the formatting, so it is never a manual step.
- Do not sort by hand. A hand-ordered class list will be re-sorted by the next person's editor, producing a diff with no meaning.
"scripts": {
"dev": "vite",
"build": "vite build",
"lint:css": "prettier --check \"src/**/*.{ts,tsx,html}\"",
"format": "prettier --write ."
}Where to put the entry import, by framework:
Vite / React / Vue SPA import "./app.css" in the main entry file
Next.js App Router import "./globals.css" in app/layout.tsx
Astro import "../styles/app.css" in the base layout
SvelteKit import "../app.css" in src/routes/+layout.svelte
Static HTML a link tag to the CLI outputFAQ
Why does @apply fail inside a Vue or Svelte component?
Scoped style blocks are compiled separately and have no access to the Tailwind theme. Add
@reference "path/to/app.css" at the top of the block so the utilities and tokens can resolve.Should I use the Vite plugin or PostCSS?
The Vite plugin when you are on Vite - it is faster and handles the ordering of the generated stylesheet for you. PostCSS when you are on a build that is not Vite, or when the framework already owns the PostCSS pipeline. Do not run both.
Related
Configuration and theming Production performance and the honest limits
Last refreshed 2026-09-18.