Tailwind Typography Plugin Tutorial
Style long-form Markdown and CMS content with the prose utility, then customize the typography plugin to fit your brand.
What you'll learn
- ✓Installing the Tailwind typography plugin
- ✓Using the prose class on rendered Markdown
- ✓Choosing prose sizes and themes
- ✓Customizing colors, headings, and code blocks
- ✓Handling dark mode
Prerequisites
- •Comfortable with HTML and JavaScript
What and Why
Tailwind is intentionally unopinionated about typography. That is great for app UIs and a problem for long-form content. The typography plugin fills the gap. One class, prose, styles every common Markdown element with sensible defaults: headings, lists, blockquotes, code blocks, tables, and inline elements. Then you customize it to match your brand.
Mental Model
The plugin generates a hierarchy of element selectors scoped to .prose. Whenever you wrap a chunk of HTML in a prose container, every nested element receives styles that look like a magazine layout. The defaults are tuned by font size variants, so prose-lg makes everything proportionally larger without you setting each element manually.
<div>
raw markdown HTML -> ugly defaults
</div>
<div class="prose">
raw markdown HTML -> readable typography
</div>
Hands-on Example
Install the plugin and add it to your config.
npm install -D @tailwindcss/typography
// tailwind.config.js
module.exports = {
content: ['./src/**/*.{astro,html,js,ts,jsx,tsx,md,mdx}'],
plugins: [require('@tailwindcss/typography')],
};
Wrap rendered content with prose.
---
import { getEntry } from 'astro:content';
const post = await getEntry('blog', Astro.params.slug);
const { Content } = await post.render();
---
<article class="prose mx-auto px-4 py-12">
<h1>{post.data.title}</h1>
<Content />
</article>
That single class gives you headings with hierarchy, lists with proper bullets, code blocks with monospaced fonts, and links with sensible underlines. The modifier classes change the scale.
<article class="prose prose-lg sm:prose-xl">
...
</article>
Customize the colors with prose modifiers.
<article class="prose prose-slate prose-headings:font-semibold
prose-a:text-blue-600 prose-a:no-underline hover:prose-a:underline
prose-code:rounded prose-code:bg-slate-100 prose-code:px-1">
...
</article>
Each prose-<element>:utility selector targets a specific Markdown element. It is a clean alternative to writing custom CSS for every tag.
For deeper changes, extend the theme. The plugin exposes the entire style object.
module.exports = {
theme: {
extend: {
typography: ({ theme }) => ({
DEFAULT: {
css: {
'--tw-prose-body': theme('colors.slate.700'),
'--tw-prose-headings': theme('colors.slate.900'),
'--tw-prose-links': theme('colors.blue.600'),
blockquote: { fontStyle: 'normal', borderLeftColor: theme('colors.blue.500') },
code: { fontWeight: '500' },
},
},
}),
},
},
plugins: [require('@tailwindcss/typography')],
};
For dark mode, the plugin ships an inverted theme.
<article class="prose dark:prose-invert">
...
</article>
The invert variant swaps body, heading, and link colors to a palette that reads well on dark backgrounds.
Common Pitfalls
Applying prose to a container that already has Tailwind utility colors fights the plugin. Strip the parent utilities or use prose modifiers like prose-p:text-current to override.
Embedded interactive components inside a prose block inherit the typography styles, which often looks wrong on buttons and cards. Use not-prose on the wrapping element to opt out.
<article class="prose">
<p>Some intro text.</p>
<div class="not-prose">
<button class="rounded bg-blue-600 px-3 py-1 text-white">Save</button>
</div>
</article>
Without not-prose, the button text would inherit prose paragraph styling and look off.
Practical Tips
Pick a max width with max-w-prose on the container. The default is around 65 characters per line, which is the sweet spot for reading. Wider lines tire the eye and shorter lines feel choppy.
If your content uses MDX components, target their root with prose modifiers or wrap them in not-prose. A custom callout component, for example, should set its own typography.
Code blocks deserve attention. Pair the typography plugin with a syntax highlighter like Shiki or Prism. The plugin styles the wrapper and the inline code, while the highlighter colors tokens inside.
Test in both light and dark mode early. Subtle color choices look fine in one mode and unreadable in the other. The prose-invert variant is a starting point, not a guarantee.
Wrap-up
The typography plugin is the fastest way to get readable long-form content in Tailwind. One class delivers a competent baseline; modifiers and theme overrides take you the rest of the way. Combine it with max-w-prose and a good syntax highlighter and your articles will look polished without writing a single line of typography CSS.
Related articles
- Tailwind Tailwind Prose and Content Styling
Use the @tailwindcss/typography plugin to style long-form content like blog posts and documentation with a single prose class and well-chosen overrides.
- Tailwind Tailwind Animation and Transition Utilities
Animate hover states, page mounts, and component transitions with Tailwind's transition and animation utilities and a few custom keyframes.
- Tailwind Tailwind Arbitrary Values and the JIT Engine
How Tailwind's JIT engine generates classes on demand, when arbitrary values are the right tool, and how to keep your design system tidy.
- Tailwind Tailwind Custom Plugins Tutorial
Write your own Tailwind plugins to add utilities, components, and variants that match your design system without reaching for arbitrary values everywhere.