tailwindcss-performance
Tailwind CSS performance optimization including v4 improvements. PROACTIVELY activate for: (1) Tailwind v4 Oxide engine performance, (2) Lightning CSS minification, (3) reducing CSS bundle size, (4) content config tuning to avoid scanning unused files, (5) safelist for dynamic classes (without bloating), (6) production builds with @apply minimization, (7) critical CSS extraction, (8) HTTP caching of generated CSS, (9) avoiding @apply overuse (utility-first preferred), (10) PurgeCSS / content-detection edge cases. Provides: performance tuning checklist, Oxide engine notes, content config patterns, safelist guidance, and critical-CSS workflow.
What this skill does
# 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:
1. Scans source files for class names
2. Generates only the CSS you use
3. Produces minimal, optimized output
### v4: Always JIT
Unlike v3, JIT is always enabled in v4—no configuration needed:
```css
@import "tailwindcss";
/* JIT is automatic */
```
## Content Detection
### Automatic Detection (v4)
v4 automatically detects template files—no content configuration required:
```css
/* v4 - Works automatically */
@import "tailwindcss";
```
### Explicit Content (v4)
If automatic detection fails, specify sources explicitly:
```css
@import "tailwindcss";
@source "./src/**/*.{html,js,jsx,ts,tsx,vue,svelte}";
@source "./components/**/*.{js,jsx,ts,tsx}";
```
### Excluding Paths
```css
@source not "./src/legacy/**";
```
## Tree Shaking
### How It Works
Tailwind's build process removes unused CSS:
```text
Source: All possible utilities (~15MB+)
↓
Scan: Find used class names
↓
Output: Only used styles (~10-50KB typical)
```
### Production Build
```bash
# 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:
```javascript
// 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
```javascript
// 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
```javascript
// 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
```css
/* In your CSS for v4 */
@source inline("text-blue-500 text-red-500 text-green-500");
```
#### 4. CSS Variables
```css
@theme {
--color-dynamic: oklch(0.6 0.2 250);
}
```
```html
<div class="text-[var(--color-dynamic)]">Dynamic color</div>
```
## Optimizing Transitions
### Use Specific Transitions
```html
<!-- 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">
```
### GPU-Accelerated Properties
Prefer `transform` and `opacity` for smooth animations:
```html
<!-- 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">
```
## CSS Variable Usage
### Prefer Native Variables
In v4, use CSS variables directly instead of `theme()`:
```css
/* 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:
```css
@import "tailwindcss/theme.css" theme(static);
```
This inlines theme values instead of using CSS variables.
## Build Optimization
### Vite Configuration
```javascript
// 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
```javascript
// postcss.config.mjs
export default {
plugins: {
'@tailwindcss/postcss': {},
cssnano: process.env.NODE_ENV === 'production' ? {} : false
}
}
```
## Reducing Bundle Size
### 1. Avoid Unused Plugins
```css
/* Only load what you need */
@plugin "@tailwindcss/typography";
/* Don't load unused plugins */
```
### 2. Limit Color Palette
```css
@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
```css
@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
```yaml
# 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
```bash
# Time your build
time npm run build
# Verbose output
DEBUG=tailwindcss:* npm run build
```
### Bundle Analysis
```bash
# Install analyzer
npm install -D vite-bundle-analyzer
# Analyze bundle
npm run build -- --analyze
```
### CSS Size Check
```bash
# 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=production` is 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:
```javascript
// Dynamically import CSS for routes
const AdminPage = lazy(() =>
import('./admin.css').then(() => import('./AdminPage'))
)
```
## Best Practices Summary
1. **Let JIT do its work** - Don't safelist unnecessarily
2. **Use complete class names** - Avoid dynamic concatenation
3. **Specific transitions** - Not `transition-all`
4. **GPU properties** - Prefer `transform` and `opacity`
5. **Minimal theme** - Only define what you use
6. **Production builds** - Always use production mode
7. **Measure** - Check your actual CSS size
Related in Web Dev
generating-lwc-components
IncludedLightning Web Components with PICKLES methodology and 165-point scoring. Use this skill when the user creates or edits LWC components, builds wire service patterns, or writes Jest tests for LWC. TRIGGER when: user creates/edits LWC components, touches lwc/**/*.js, .html, .css, .js-meta.xml files, or asks about wire service, SLDS, or Jest LWC tests. DO NOT TRIGGER when: Apex classes (use generating-apex), Aura components, or Visualforce.
tanstack-query
IncludedManage server state in React with TanStack Query v5. Set up queries with useQuery, mutations with useMutation, configure QueryClient caching strategies, implement optimistic updates, and handle infinite scroll with useInfiniteQuery. Use when: setting up data fetching in React projects, migrating from v4 to v5, or fixing object syntax required errors, query callbacks removed issues, cacheTime renamed to gcTime, isPending vs isLoading confusion, keepPreviousData removed problems.
document-processor-api
IncludedProcess documents with Nutrient DWS. Use when the user wants to generate PDFs from HTML or URLs, convert Office/images/PDFs, assemble or split packets, OCR scans, extract text/tables/key-value pairs, redact PII, watermark, sign, fill forms, optimize PDFs, or produce compliance outputs like PDF/A or PDF/UA. Triggers include convert to PDF, merge these PDFs, OCR this scan, extract tables, redact PII, sign this PDF, make this PDF/A, or linearize for web delivery.
nutrient-document-processing
IncludedProcess documents with Nutrient DWS. Use when the user wants to generate PDFs from HTML or URLs, convert Office/images/PDFs, assemble or split packets, OCR scans, extract text/tables/key-value pairs, redact PII, watermark, sign, fill forms, optimize PDFs, or produce compliance outputs like PDF/A or PDF/UA. Triggers include convert to PDF, merge these PDFs, OCR this scan, extract tables, redact PII, sign this PDF, make this PDF/A, or linearize for web delivery.
tanstack-query
IncludedManage server state in React with TanStack Query v5. Covers useMutationState, simplified optimistic updates, throwOnError, network mode (offline/PWA), and infiniteQueryOptions. Use when setting up data fetching, fixing v4→v5 migration errors (object syntax, gcTime, isPending, keepPreviousData), or debugging SSR/hydration issues with streaming server components.
accelint-nextjs-best-practices
IncludedNext.js performance optimization and best practices. Use when writing Next.js code (App Router or Pages Router); implementing Server Components, Server Actions, or API routes; optimizing RSC serialization, data fetching, or server-side rendering; reviewing Next.js code for performance issues; fixing authentication in Server Actions; or implementing Suspense boundaries, parallel data fetching, or request deduplication.