Tailwind Typography Plugin
Style Markdown and CMS HTML with prose classes.
A practical, copy-pasteable guide to @tailwindcss/typography
: install it, drop in the prose
class, tune sizes and colors, and keep “HTML you don’t control” (Markdown, CMS output) looking clean and consistent.
What the Typography plugin solves
Blog posts, docs, and CMS pages ship a lot of raw HTML: headings, lists, tables, code blocks, images. The Typography plugin adds opinionated styles to that content via a single prose
class, so your long-form text looks great without hand-authoring CSS for every tag.
a good typography example from Alfred theme
a beautiful blog post using prose classes from Navy theme
Installation
Tailwind v4 (CSS-first)
Add the plugin right in your CSS:
/* app.css (or main.css) */
@import "tailwindcss";
@plugin "@tailwindcss/typography";
That is the new v4 way to enable first-party plugins.
Tailwind v3 (legacy projects)
// tailwind.config.js
module.exports = {
plugins: [require("@tailwindcss/typography")],
};
This is still fully supported in v3.
Compatibility note: the plugin added explicit support for Tailwind v4 in recent releases. If you upgraded Tailwind, update
@tailwindcss/typography
too.
Basic usage
Wrap your CMS or Markdown output in .prose
:
<article class="prose">
<h1>Garlic bread with cheese</h1>
<p>…all your paragraphs, lists, tables, and images go here…</p>
</article>
You can scale the whole type system at breakpoints:
<article class="prose md:prose-lg lg:prose-xl">
<!-- content -->
</article>
Those size modifiers are built in: prose-sm
, prose-base
(default), prose-lg
, prose-xl
, prose-2xl
.
Remove the built-in max-width when you need full-bleed content:
<article class="prose max-w-none">
<!-- content -->
</article>
The plugin ships a comfortable reading width by default; max-w-none
opt-out is the sanctioned override.
Color themes and dark mode
Pick a gray theme that matches your brand palette:
<article class="prose prose-slate">…</article>
<!-- also: prose-zinc, prose-neutral, prose-stone -->
Then invert for dark mode:
<article class="prose dark:prose-invert">
…
</article>
The plugin provides prose-invert
for one-line dark color adjustments.
Heads-up: some users report that combining
prose-invert
with a gray theme likeprose-stone
can clash under v4. If you hit that, track the issue and either drop the gray theme in dark mode or force priority with!prose-invert
.
Target a single element with “element modifiers”
You can keep the global defaults and still tweak any element inline:
<article
class="prose prose-a:text-indigo-600 prose-a:underline hover:prose-a:text-indigo-500 prose-img:rounded-xl prose-code:before:content-none prose-code:after:content-none"
>
<!-- links use your brand color, images have rounded corners, code fence quotes removed -->
</article>
Available targets include prose-headings
, prose-a
, prose-img
, prose-code
, prose-pre
, prose-table
, prose-kbd
, and many more. In v4, when stacking modifiers like hover
, put the non-prose modifier last, as in the example above.
Keep playgrounds and widgets unstyled with not-prose
When you embed UI inside an article (like a code demo or pricing card), fence it off:
<article class="prose">
<p>Intro text…</p>
<div class="not-prose">
<!-- your component here stays untouched by prose styles -->
</div>
<p>Back to the article…</p>
</article>
not-prose
prevents unwanted inheritance and is the recommended escape hatch.
Customize the defaults (two approaches)
1) Quick, inline utilities with element modifiers
Best for small tweaks that live next to the markup, as shown earlier.
2) Deeper theme overrides (colors, spacing, code blocks, etc.)
If you need to change the generated CSS itself, enable JS config in v4 with @config
, then extend the typography
theme object:
/* app.css */
@import "tailwindcss";
@plugin "@tailwindcss/typography";
@config "./tailwind.config.js";
// tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
theme: {
extend: {
typography: {
DEFAULT: {
css: {
a: { color: "var(--color-indigo-600)", "&:hover": { color: "var(--color-indigo-500)" } },
"h1, h2, h3": { scrollMarginTop: "var(--spacing-24)" },
code: { fontWeight: "600" },
},
},
},
},
},
};
That pattern is also how you add a brand color theme, or tune the plugin’s dark tokens.
Rename the prose class (optional)
Prefer wysiwyg
or content
instead of prose
? You can change it when registering the plugin in v4:
@import "tailwindcss";
@plugin "@tailwindcss/typography" { className: wysiwyg; }
Use wysiwyg
, wysiwyg-slate
, lg:wysiwyg-xl
, and not-wysiwyg
thereafter.
Common pitfalls and fixes
Utilities “don’t work” inside
.prose
children. The plugin’s element selectors are quite specific, so a bareclass="text-red-500"
on anh2
might be trumped. Use element modifiers likeprose-h2:text-red-500
, or apply deeper theme overrides.No styles after upgrading to v4. Ensure you added
@plugin "@tailwindcss/typography";
in your CSS and updated the plugin to a v4-compatible release.
Copy-paste starters
Blog article scaffold
<main class="mx-auto max-w-3xl px-4 py-12">
<article class="prose prose-slate md:prose-lg lg:prose-xl dark:prose-invert">
<h1>Master Tailwind Typography for Blogs</h1>
<p class="lead">A clean baseline for Markdown or CMS HTML.</p>
<h2>Why it matters</h2>
<p>Readable defaults save hours of CSS tweaks…</p>
<pre><code>// fenced code block</code></pre>
<figure>
<img src="/cover.jpg" alt="Cover" />
<figcaption>A helpful caption lives here.</figcaption>
</figure>
<table>
<thead><tr><th>Package</th><th>Version</th></tr></thead>
<tbody><tr><td>@tailwindcss/typography</td><td>latest</td></tr></tbody>
</table>
<div class="not-prose my-8">
<!-- embedded demo or CTA -->
<button class="px-4 py-2 rounded bg-indigo-600 text-white">Call to Action</button>
</div>
</article>
</main>
Minimal v4 CSS to enable the plugin
@import "tailwindcss";
@plugin "@tailwindcss/typography";
Both snippets follow the official v4 approach and the plugin’s documented API.
TL;DR checklist
Add the plugin:
@plugin "@tailwindcss/typography";
(v4) orplugins: [require("@tailwindcss/typography")]
(v3).Wrap content in
.prose
; scale withmd:prose-lg
,lg:prose-xl
.Pick a gray theme (
prose-slate
etc.) and invert in dark mode (dark:prose-invert
).Use element modifiers for one-off tweaks (
prose-a:*
,prose-img:*
,prose-code:*
).Use
not-prose
for embedded components;max-w-none
to remove the reading-width cap.For deep customization, enable
@config
and extendtheme.typography
.
FAQ
How do I install it in Tailwind v4 vs. v3?
In v4, add the plugin in your CSS: @import "tailwindcss"; @plugin "@tailwindcss/typography";. In v3, add require('@tailwindcss/typography') to plugins in tailwind.config.js.
How do I enable dark mode for article content?
Use dark:prose-invert on the same element that has prose. You can also pick a gray theme like prose-slate to match your site’s palette.
How can I stop the plugin from styling an embedded widget or demo?
Wrap the widget in a not-prose container inside your .prose article. Note: you can’t nest a new .prose inside a not-prose block.
Why is my article width capped, and how do I make it full-width?
The plugin ships a comfortable reading max-width. Add max-w-none to the .prose element to let content fill its container.
What’s the best way to customize specific elements (links, code, headings)?
Use element modifiers like prose-a:text-blue-600, prose-img:rounded-xl, etc. In v4, when stacking with other modifiers (e.g., hover), put the non-prose modifier last. For deeper changes, extend theme.typography via @config.

Yucel is a digital product creator and content writer with a knack for full-stack development. He loves blending technical know-how with engaging storytelling to build practical, user-friendly solutions. When he's not coding or writing, you'll likely find him exploring new tech trends or getting inspired by nature.