Content Detection / Purge
Tailwind purge / content scanning: how unused classes get removed from production CSS. (Now built into JIT.)
Tailwind — purge / content
EXAMPLE
<!-- ===== History ===== -->
<!--
Tailwind v2: 'purge' option ran PostCSS plugin at build time.
Tailwind v3: 'content' option drives JIT compilation.
Tailwind v4: 'content' auto-detected from your project structure.
The principle is the same: only ship CSS for classes you actually use.
-->
// tailwind.config.js (v3)
export default {
content: [
'./index.html',
'./src/**/*.{js,ts,jsx,tsx,vue,svelte}',
],
theme: { extend: {} },
plugins: [],
};
// Tailwind scans these files for class names and only emits those classes.
// ===== What gets scanned =====
// JIT looks for STRING literals that match class names.
// It's greedy: any string in your code can be a class.
// Tradeoff: false positives (CSS shipped you didn't use) vs simplicity.
// ===== Dynamic class names ===== =====
// JIT cannot see classes constructed dynamically:
const color = 'red';
<div class={\`bg-${color}-500\`} /> // BAD — JIT sees 'bg-' + '-500', not 'bg-red-500'
// Fix 1: spell out all options
const colorClasses = { red: 'bg-red-500', green: 'bg-green-500', blue: 'bg-blue-500' };
<div class={colorClasses[color]} />
// Fix 2: safelist
// tailwind.config.js
safelist: [
'bg-red-500',
'bg-green-500',
{ pattern: /bg-(red|green|blue)-(100|500|900)/ },
],
// ===== Production build =====
NODE_ENV=production npm run build
// Tailwind runs in JIT mode; output is minimised.
// ===== Inspecting output =====
// Build, then check dist/styles.css size.
// Typical sizes:
// - Small SPA: 10-30 KB minified
// - Large SPA: 50-100 KB minified
// - Pre-Tailwind / unpurged: 3+ MB
// ===== Include external component libraries =====
content: [
'./src/**/*.{ts,tsx}',
'./node_modules/@my-org/ui/**/*.js', // libraries you depend on
],
// Otherwise their classes get purged in your build.
// ===== Common bugs =====
// - Classes 'mysteriously missing' from production build -> dynamic class names
// - Content paths missing a folder -> classes never appear
// - node_modules / dist included -> huge build files scanned
// - safelist drift -> classes survive long after the dynamic source is removed
// ===== Patterns =====
// - Wide content globs that match your source code
// - Spell out class names statically when possible
// - Use safelist with REGEX PATTERN for dynamic colour / size
// - Audit safelist when refactoring
// ===== Pitfalls =====
// - Including node_modules of unrelated libs -> slow build
// - Forgetting that mdx / html / pug / liquid files need explicit globs
// - Safelist with no expiry -> dead classes ship forever
// - Class names built from arrays of strings -> JIT sees individual strings
Why it matters
JIT / content scanning ships only the classes you use. Spell out class names statically, safelist dynamic ones, point content paths at every source file. Production builds typically land 10-100 KB minified — orders of magnitude smaller than the old purge era.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
// content: ['./src/**/*.{html,js,jsx,ts,tsx}'] — anything outside is purged.
Try it Yourself »
Discussion
Loading…