Overview
Tailwind v4 replaced the JavaScript plugin API with a CSS-native @plugin directive. First-party plugins (typography, forms, container-queries) load with one line. Custom utilities and variants live in plain CSS. The parent reference is tailwind.
Load first-party plugins with @plugin
Add a first-party plugin the same way you would add any CSS import.
@import "tailwindcss";
@plugin "@tailwindcss/typography";
@plugin "@tailwindcss/forms";
@plugin "@tailwindcss/container-queries";Install the package first: npm install @tailwindcss/typography. No JavaScript config file needed.
@tailwindcss/typographyadds theproseclass for rich text bodies:<article class="prose">.@tailwindcss/formsresets form elements to a consistent baseline without killing customization.@tailwindcss/container-queriesadds@lg:,@md:, and other container-size variants. For the underlying CSS mechanism, see css-container-queries.
Customize first-party plugins with @theme overrides
Typography and forms both read from your @theme tokens. Override them by setting the relevant custom properties after the @plugin line.
@plugin "@tailwindcss/typography";
@theme {
--tw-prose-body: var(--color-ink);
--tw-prose-headings: var(--color-ink);
--tw-prose-links: var(--color-brand-500);
--tw-prose-code: var(--color-brand-700);
}This keeps prose colors in sync with the design system instead of hard-coding a parallel set of values.
Write custom utilities as CSS in @layer utilities
For utilities that no plugin covers, write them directly in the utilities layer. They become first-class Tailwind utilities: they participate in the scanner, the Prettier sort, and the variant system.
@layer utilities {
.text-balance {
text-wrap: balance;
}
.scrollbar-none {
scrollbar-width: none;
}
.scrollbar-none::-webkit-scrollbar {
display: none;
}
}Use this for single-property utilities that would otherwise be arbitrary values you type repeatedly. Three or more uses of [text-wrap:balance] in source means it belongs here.
Write custom variants with @custom-variant
Define a custom variant for any CSS selector pattern you repeat.
@custom-variant hocus (&:hover, &:focus-visible);
@custom-variant rtl ([dir="rtl"] &);
@custom-variant print (@media print { & });After this definition, hocus:text-brand applies text-brand on hover or keyboard focus. The rtl: variant flips layout for right-to-left languages. print:hidden hides elements in print media.
Publish reusable plugin packages as CSS files
A v4 plugin is a plain CSS file that follows the @layer and @theme conventions. Publish it to npm; consumers load it with @plugin.
/* my-plugin/index.css */
@layer utilities {
.truncate-2 {
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
}/* consumer */
@plugin "my-plugin";No build step, no JavaScript file, no plugin function to call. The CSS file is the plugin.
Check v4 before reaching for a v3 plugin
Several popular v3 plugins became built-in or first-class in v4:
@tailwindcss/line-clamp: theline-clamp-*utilities are built into v4.@tailwindcss/aspect-ratio:aspect-*utilities are built in.@tailwindcss/typography: still separate; see above.- Custom
theme()calls in v3: replaced byvar(--token-name)in v4 since tokens are CSS custom properties.
Checking the v4 changelog before installing a plugin avoids pulling in a package that does nothing.
Avoid composing utilities with @apply inside plugins
@apply inside a plugin adds hidden coupling between the plugin and the host project’s utility set. If the host project renames a token, the plugin silently breaks.
Write plugins using direct CSS declarations and var(--token) references. This makes the dependency on the design system explicit and auditable.