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 --minify

One 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-rulePurpose
@import "tailwindcss"Loads the whole framework
@themeDeclares design tokens
@layer componentsRegisters your own component classes
@utilityRegisters a custom utility that works with variants
@applyInlines utilities into a rule
@referenceGives a scoped style block access to the theme
@variantApplies 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 output

FAQ

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.

Configuration and theming Production performance and the honest limits

Last refreshed 2026-09-18.