tailwindcss-performance
Tailwind CSS Performance Optimization
v4 Performance Improvements
Tailwind CSS v4 features a completely rewritten engine in Rust:
| Metric | v3 | v4 |
|---|---|---|
| Full builds | Baseline | Up to 5x faster |
| Incremental builds | Milliseconds | Microseconds (100x+) |
| Engine | JavaScript | Rust |
JIT (Just-In-Time) Compilation
How JIT Works
JIT generates styles on-demand as classes are discovered in your files:
- Scans source files for class names
- Generates only the CSS you use
- Produces minimal, optimized output
v4: Always JIT
Unlike v3, JIT is always enabled in v4—no configuration needed:
@import "tailwindcss";
/* JIT is automatic */
Content Detection
Automatic Detection (v4)
v4 automatically detects template files—no content configuration required:
/* v4 - Works automatically */
@import "tailwindcss";
Explicit Content (v4)
If automatic detection fails, specify sources explicitly:
@import "tailwindcss";
@source "./src/**/*.{html,js,jsx,ts,tsx,vue,svelte}";
@source "./components/**/*.{js,jsx,ts,tsx}";
Excluding Paths
@source not "./src/legacy/**";
Tree Shaking
How It Works
Tailwind's build process removes unused CSS:
Source: All possible utilities (~15MB+)
↓
Scan: Find used class names
↓
Output: Only used styles (~10-50KB typical)
Production Build
# Vite - automatically optimized for production
npm run build
# PostCSS - ensure NODE_ENV is set
NODE_ENV=production npx postcss input.css -o output.css
Dynamic Class Names
The Problem
Tailwind can't detect dynamically constructed class names:
// BAD - Classes won't be generated
const color = 'blue'
className={`text-${color}-500`} // ❌ Not detected
const size = 'lg'
className={`text-${size}`} // ❌ Not detected
Solutions
1. Use Complete Class Names
// GOOD - Full class names
const colorClasses = {
blue: 'text-blue-500',
red: 'text-red-500',
green: 'text-green-500',
}
className={colorClasses[color]} // ✓ Detected
2. Use Data Attributes
// GOOD - Style based on data attributes
<div data-color={color} className="data-[color=blue]:text-blue-500 data-[color=red]:text-red-500">
3. Safelist Classes
/* In your CSS for v4 */
@source inline("text-blue-500 text-red-500 text-green-500");
4. CSS Variables
@theme {
--color-dynamic: oklch(0.6 0.2 250);
}
<div class="text-[var(--color-dynamic)]">Dynamic color</div>
Optimizing Transitions
Use Specific Transitions
<!-- SLOW - Transitions all properties -->
<button class="transition-all duration-200">
<!-- FAST - Only transitions specific properties -->
<button class="transition-colors duration-200">
<button class="transition-transform duration-200">
<button class="transition-opacity duration-200"></button>
</button>
</button>
</button>
GPU-Accelerated Properties
Prefer transform and opacity for smooth animations:
<!-- GOOD - GPU accelerated -->
<div class="transform hover:scale-105 transition-transform">
<!-- GOOD - GPU accelerated -->
<div class="opacity-100 hover:opacity-80 transition-opacity">
<!-- SLOW - May cause repaints -->
<div class="left-0 hover:left-4 transition-all"></div>
</div>
</div>
CSS Variable Usage
Prefer Native Variables
In v4, use CSS variables directly instead of theme():
/* v3 - Uses theme() function */
.element {
color: theme(colors.blue.500);
}
/* v4 - Use CSS variables (faster) */
.element {
color: var(--color-blue-500);
}
Static Theme Values
For performance-critical paths:
@import "tailwindcss/theme.css" theme(static);
This inlines theme values instead of using CSS variables.
Build Optimization
Vite Configuration
// vite.config.js
import tailwindcss from "@tailwindcss/vite";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [tailwindcss()],
build: {
// Minify CSS
cssMinify: "lightningcss",
// Optimize chunks
rollupOptions: {
output: {
manualChunks: {
// Split vendor CSS if needed
},
},
},
},
});
PostCSS with cssnano
// postcss.config.mjs
export default {
plugins: {
"@tailwindcss/postcss": {},
cssnano: process.env.NODE_ENV === "production" ? {} : false,
},
};
Reducing Bundle Size
1. Avoid Unused Plugins
/* Only load what you need */
@plugin "@tailwindcss/typography";
/* Don't load unused plugins */
2. Limit Color Palette
@theme {
/* Disable default colors */
--color-*: initial;
/* Define only needed colors */
--color-primary: oklch(0.6 0.2 250);
--color-secondary: oklch(0.7 0.15 180);
--color-gray-100: oklch(0.95 0 0);
--color-gray-900: oklch(0.15 0 0);
}
3. Limit Breakpoints
@theme {
/* Remove unused breakpoints */
--breakpoint-2xl: initial;
/* Keep only what you use */
--breakpoint-sm: 640px;
--breakpoint-md: 768px;
--breakpoint-lg: 1024px;
}
Caching Strategies
Development
- v4's incremental builds are already extremely fast
- No additional caching needed in most cases
CI/CD
# GitHub Actions example
- name: Cache node_modules
uses: actions/cache@v4
with:
path: node_modules
key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}
- name: Build
run: npm run build
Measuring Performance
Build Time Analysis
# Time your build
time npm run build
# Verbose output
DEBUG=tailwindcss:* npm run build
Bundle Analysis
# Install analyzer
npm install -D vite-bundle-analyzer
# Analyze bundle
npm run build -- --analyze
CSS Size Check
# Check output CSS size
ls -lh dist/assets/*.css
# Gzipped size
gzip -c dist/assets/main.css | wc -c
Performance Checklist
Development
- JIT is working (styles update instantly)
- No console warnings about large files
- Hot reload is fast
Production
-
NODE_ENV=productionis set - CSS is minified
- Unused CSS is removed
- No dynamic class name issues
- CSS size is reasonable (<50KB typical)
Common Issues
| Issue | Solution |
|---|---|
| Large CSS output | Check for dynamic classes, safelist issues |
| Slow builds | Ensure v4, check file globs |
| Missing styles | Check content detection, class names |
| Slow animations | Use GPU-accelerated properties |
Lazy Loading CSS
For very large apps, consider code-splitting CSS:
// Dynamically import CSS for routes
const AdminPage = lazy(() =>
import("./admin.css").then(() => import("./AdminPage")),
);
Best Practices Summary
- Let JIT do its work - Don't safelist unnecessarily
- Use complete class names - Avoid dynamic concatenation
- Specific transitions - Not
transition-all - GPU properties - Prefer
transformandopacity - Minimal theme - Only define what you use
- Production builds - Always use production mode
- Measure - Check your actual CSS size
More from frostfoe7/rdz
next-best-practices
Next.js best practices - file conventions, RSC boundaries, data patterns, async APIs, metadata, error handling, route handlers, image/font optimization, bundling
17web-design-guidelines
Review UI code for Web Interface Guidelines compliance. Use when asked to "review my UI", "check accessibility", "audit design", "review UX", or "check my site against best practices".
14ui-ux-pro-max
UI/UX design intelligence for web and mobile. Includes 50+ styles, 161 color palettes, 57 font pairings, 161 product types, 99 UX guidelines, and 25 chart types across 10 stacks (React, Next.js, Vue, Svelte, SwiftUI, React Native, Flutter, Tailwind, shadcn/ui, and HTML/CSS). Actions: plan, build, create, design, implement, review, fix, improve, optimize, enhance, refactor, and check UI/UX code. Projects: website, landing page, dashboard, admin panel, e-commerce, SaaS, portfolio, blog, and mobile app. Elements: button, modal, navbar, sidebar, card, table, form, and chart. Styles: glassmorphism, claymorphism, minimalism, brutalism, neumorphism, bento grid, dark mode, responsive, skeuomorphism, and flat design. Topics: color systems, accessibility, animation, layout, typography, font pairing, spacing, interaction states, shadow, and gradient. Integrations: shadcn/ui MCP for component search and examples.
12typescript-advanced-types
Master TypeScript's advanced type system including generics, conditional types, mapped types, template literals, and utility types for building type-safe applications. Use when implementing complex type logic, creating reusable type utilities, or ensuring compile-time type safety in TypeScript projects.
11shadcn
Manages shadcn components and projects — adding, searching, fixing, debugging, styling, and composing UI. Provides project context, component docs, and usage examples. Applies when working with shadcn/ui, component registries, presets, --preset codes, or any project with a components.json file. Also triggers for "shadcn init", "create an app with --preset", or "switch to --preset".
8tailwindcss-advanced-layouts
Tailwind CSS advanced layout techniques including CSS Grid and Flexbox patterns
4