Two problems come up in almost every project and are awkward to solve with utilities alone: styling large blocks of HTML you do not control (Markdown, CMS output, comments) and making native form controls look consistent across browsers. Tailwind's official plugins solve both. In this lesson you will learn how plugins are loaded in v4, how the prose classes work, how the forms plugin resets controls, and which former plugins are now built in.
Plugins are npm packages registered with the @plugin directive in your main stylesheet — no JavaScript config is involved:
npm install -D @tailwindcss/typography @tailwindcss/forms@import "tailwindcss";
@plugin "@tailwindcss/typography";
@plugin "@tailwindcss/forms";Options are passed in a block after the name, for example @plugin "@tailwindcss/forms" { strategy: class; }. The directive accepts a package name or a relative path, so the same mechanism loads a plugin you write yourself.
Add prose to a wrapper and every descendant heading, paragraph, list, table, blockquote, image and code block receives carefully tuned defaults:
<article class="prose prose-slate lg:prose-xl dark:prose-invert">
<!-- rendered Markdown goes here -->
</article>| Modifier | Effect |
|---|---|
| prose-sm, prose-base, prose-lg, prose-xl, prose-2xl | Overall type scale, responsive with lg:prose-xl |
| prose-gray (default), prose-slate, prose-zinc, prose-neutral, prose-stone | Gray palette for text and rules |
| prose-invert | Light-on-dark colors, usually as dark:prose-invert |
| max-w-none | Removes the built-in 65ch reading width |
Individual elements are customised with element modifiers, which take any utility:
<article class="prose prose-headings:font-semibold prose-a:text-blue-600 prose-a:no-underline
hover:prose-a:underline prose-img:rounded-xl prose-code:before:content-none">There is a modifier for every element the plugin styles (prose-h1, prose-p, prose-blockquote, prose-code, prose-pre, prose-li, prose-table, prose-hr and so on). To exclude a block such as an embedded component, wrap it in not-prose.
Use prose only around content you do not author with utilities; on a whole page it fights every component.
Browsers ship inconsistent, hard-to-override styles for inputs, selects, checkboxes and radios. The forms plugin resets them to plain boxes with sensible padding and borders, so ordinary utilities work:
<label class="block text-sm font-medium">Plan
<select class="mt-1 block w-full rounded-md border-gray-300 focus:border-blue-500 focus:ring-blue-500">
<option>Monthly</option>
</select>
</label>
<label class="flex items-center gap-2">
<input type="checkbox" class="rounded border-gray-300 text-blue-600 focus:ring-blue-500" />
Send me updates
</label>Note that text-blue-600 on a checkbox sets its checked color, and that rounded works on it — both impossible without the reset. By default the plugin styles every form element globally. The class strategy (strategy: class) applies the reset only to elements carrying form-input, form-select, form-checkbox, form-radio, form-textarea or form-multiselect, which is safer in a codebase with pre-existing form styles.
Several v3 plugins became core features in v4:
@tailwindcss/container-queries — the @container and @sm: variants are built in.@tailwindcss/aspect-ratio — use aspect-video, aspect-square or aspect-3/2.@tailwindcss/line-clamp — line-clamp-* is built in since v3.3.Remove them from package.json during an upgrade to avoid duplicate CSS.
@plugin in the stylesheet, so nothing changes.@plugin in a component CSS file instead of the file that imports Tailwind.strategy: class.prose around utility-styled components without not-prose.How is a plugin registered in Tailwind v4?
@plugin "package" in the stylesheet that imports Tailwind; pass options in a block.prose styles untrusted rich text; tune it with size, gray, prose-invert and element modifiers, and opt out with not-prose.rounded-md and text-blue-600 work on them; strategy: class limits the reset.Next lesson: Building a Responsive Navbar with a Mobile Menu — combine flexbox, breakpoints and state variants into a real navigation component.