the three wiring directives — at a glance
v4 is configured in CSS, not JS. These three at-rules are how you wire
Tailwind into a real build pipeline (CLI / Vite / PostCSS). They
replace v3's tailwind.config.js knobs: plugins:[],
scoped-style hacks, and addVariant(). None of them produce
classes by themselves — they extend what Tailwind knows or
emits.
| directive | one-line job | replaces (v3) | runs in CDN? |
|---|---|---|---|
@plugin |
load a JS plugin (official or 3rd-party) and optionally pass it options | plugins: ["@tailwindcss/typography"] in config |
no — needs npm resolution |
@reference |
import theme + utilities into a scoped style (Vue/Svelte/CSS modules) for @apply without duplicating output |
no equivalent — v3 needed workarounds / @layer hacks | no — needs a build graph |
@variant |
apply a variant from inside your own CSS (hover, dark, custom) | leaving CSS for a hover: utility class |
YES — see Panel 5 |
1 · @plugin — load official & custom plugins simulated
The Play CDN cannot resolve npm packages, so this panel is a faithful
simulation of what a real build (npm i -D @tailwindcss/typography
then @plugin "@tailwindcss/typography";) produces. The
source on the left is what you write; the table lists the official
plugins and what each ships.
| official plugin | installs | v4 status |
|---|---|---|
@tailwindcss/typography |
.prose, prose-sm…prose-xl, prose-invert, prose-{color} — opinionated long-form text styling |
JS plugin — load via @plugin |
@tailwindcss/forms |
resets + consistent styling for input, select, checkbox, radio across browsers |
JS plugin — load via @plugin |
@tailwindcss/aspect-ratio |
aspect-w-* / aspect-h-* (pre-aspect-ratio CSS shim) |
largely obsolete — use built-in aspect-* |
@tailwindcss/line-clamp |
line-clamp-* |
built into v4 core — do NOT install |
@tailwindcss/container-queries |
@container + @sm:…@7xl: variants |
built into v4 core — do NOT install |
💡 Custom plugins are JS files exporting ({ addUtilities, addVariant, theme, … }) => { … }
— the v3 API still works under @plugin. But for new,
static behavior prefer the CSS-first directives (@utility,
@custom-variant, @theme) which need no JS and
work everywhere. See @utility.
2 · what @plugin "@tailwindcss/typography" actually buys you simulated
Same HTML on both sides. Left = raw browser defaults. Right = the
.prose class (here simulated by fake-prose, a
hand-built @utility). The real plugin also does code-block
styling, table borders, quote marks, and per-element color theming —
but the rhythm + heading scale + link treatment below is the
headline value.
raw HTML (no prose)
Shipping faster
The deploy loop
Most teams think deploys are about CI speed. They are really about feedback.
- push small
- ship often
with fake-prose (≈ .prose)
Shipping faster
The deploy loop
Most teams think deploys are about CI speed. They are really about feedback.
- push small
- ship often
The "after" side is rendered by the @utility fake-prose +
nested selectors in this page's <style type="text/tailwindcss">.
That is a CSS-first, CDN-runnable stand-in; the real prose
class comes from @plugin "@tailwindcss/typography" in a build.
3 · @reference — make @apply work inside Vue/Svelte scoped styles build-only
Component frameworks (Vue SFCs, Svelte, CSS modules) compile each
<style> in isolation. If you write
@apply text-cyan-400 there, the compiler has no idea what
text-cyan-400 is — it lives in your root Tailwind import.
@reference imports the theme + utilities for resolution
only: the symbols become visible, but Tailwind's CSS is not
emitted again (no duplication across every component file).
| you write | when to use it |
|---|---|
@reference "tailwindcss"; |
scoped style that only needs the default theme (no @theme/@plugin/@custom-variant of your own) |
@reference "../../app.css"; |
scoped style that needs your tokens/variants — point at the file that does @import "tailwindcss" + your customizations |
@reference "#app.css"; |
subpath import via package.json "imports" map (CLI / Vite / PostCSS only) |
⚠️ @reference is not @import.
@import "tailwindcss" emits Tailwind's full CSS wherever it
appears (you'd duplicate it per component). @reference emits
nothing — it only teaches the local compiler about the symbols.
4 · @variant — apply a variant from inside your CSS live
Instead of leaving your stylesheet for a hover: / dark:
utility, use @variant inline. The button below is styled by
ONE rule — .demo-btn — defined in this page's
<style type="text/tailwindcss"> block. Its
hover and a custom pressed (= :active)
variant are emitted by the CDN right now. Hover then click it.
base: —
hover: —
@variant accepts any variant — built-in (hover,
focus, dark, md) or one you
registered with @custom-variant (here: pressed).
It's the in-CSS twin of the variant: class prefix.
intent → directive
| intent | directive | example |
|---|---|---|
use the typography plugin's .prose |
@plugin |
@plugin "@tailwindcss/typography"; |
rename .prose to a custom class |
@plugin { … } |
@plugin "@tailwindcss/typography" { className: "wysiwyg"; } |
@apply inside a Vue <style scoped> |
@reference |
@reference "tailwindcss"; (default) or @reference "../../app.css"; (your tokens) |
apply hover from inside CSS |
@variant |
.x { color:black; @variant hover { color:white; } } |
| apply a custom variant from inside CSS | @custom-variant + @variant |
@custom-variant pressed (&:active); then @variant pressed { … } |
| add a brand-new static utility (no JS) | @utility |
@utility tab-4 { tab-size: 4; } — see functional utility |