Writing Plugins
Tailwind plugins: official (typography, forms, container-queries) and custom plugin authoring.
Tailwind — plugins
EXAMPLE
// ===== Install official plugins =====
npm install -D @tailwindcss/typography @tailwindcss/forms @tailwindcss/container-queries
// tailwind.config.js
import typography from '@tailwindcss/typography';
import forms from '@tailwindcss/forms';
import containerQueries from '@tailwindcss/container-queries';
export default {
content: [...],
theme: { extend: {} },
plugins: [typography, forms, containerQueries],
};
// ===== Typography (prose-* classes) =====
<article class="prose prose-slate dark:prose-invert prose-lg max-w-prose">
<h1>Title</h1>
<p>Long-form content. Paragraphs, lists, blockquotes, code blocks all get sensible defaults.</p>
<pre><code>const x = 1;</code></pre>
</article>
// Useful for blog posts, docs, MDX rendered output.
// ===== Forms =====
// Adds modest base styles to form controls (checkbox, radio, select, input).
<input type="text" class="rounded border-slate-300 focus:border-blue-500 focus:ring-blue-500" />
<select class="rounded">
<option>One</option>
</select>
// You can then opt-out per element with:
<input type="text" class="form-input-unset" />
// ===== Container queries =====
<div class="@container">
<div class="grid grid-cols-1 @md:grid-cols-2 @lg:grid-cols-3">
<div>Item</div>
<div>Item</div>
<div>Item</div>
</div>
</div>
// Use @container instead of media queries when the container size matters more than viewport.
// ===== Custom plugin =====
// tailwind.config.js
import plugin from 'tailwindcss/plugin';
const animatedUnderline = plugin(function ({ addUtilities, theme }) {
addUtilities({
'.animated-underline': {
'position': 'relative',
'&::after': {
'content': '""',
'position': 'absolute',
'left': '0',
'bottom': '-2px',
'height': '2px',
'width': '100%',
'background': theme('colors.blue.500'),
'transform': 'scaleX(0)',
'transition': 'transform 200ms',
},
'&:hover::after': {
'transform': 'scaleX(1)',
},
},
});
});
export default {
// ...
plugins: [animatedUnderline],
};
// ===== Plugin types =====
// addUtilities adds new utility classes
// addComponents adds repeatable component classes
// addBase adds base styles (resets, html selector)
// addVariant adds new variant prefix (e.g. peer-checked)
// matchUtilities for dynamic utility names with values
// ===== matchUtilities (advanced) =====
const truncateMulti = plugin(function ({ matchUtilities, theme }) {
matchUtilities(
{
'truncate-lines': (value) => ({
'display': '-webkit-box',
'-webkit-line-clamp': String(value),
'-webkit-box-orient': 'vertical',
'overflow': 'hidden',
}),
},
{ values: theme('lineClamp') }
);
});
// Now: <p class="truncate-lines-3">...</p> works.
// ===== Discovering plugins =====
// - Awesome Tailwind CSS
// - Tailwind UI (paid; high-quality components)
// - daisyUI (free component lib as plugin)
// - flowbite, headlessui adapters
// ===== Patterns =====
// - typography for long-form content
// - forms for default form styling
// - container-queries when component-level responsive matters
// - Custom plugins for repeated bespoke patterns
// ===== Pitfalls =====
// - Overusing typography on UI-heavy pages
// - forms styling conflicting with UI lib defaults
// - Custom plugin maintained without tests across Tailwind upgrades
// - Distributing internal-style helpers as plugins (overkill)
Why it matters
Tailwind plugins extend the utility set. Official: typography for prose, forms for inputs, container-queries for component-level responsive. Custom plugins via addUtilities / addComponents / matchUtilities when you need bespoke shapes. Most apps need just the typography + forms plugins; custom plugins arrive later if needed.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
// plugins: [require('@tailwindcss/forms'), require('@tailwindcss/typography')]
Try it Yourself »
Discussion
Loading…