- Add package.json with Tailwind dependencies - Add tailwind.config.js and postcss.config.js - Add source tailwind.css file - Generate tailwind.output.css for admin and vendor - Add Tailwind CSS documentation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
6.8 KiB
Tailwind CSS Build Guide
Version: 1.0 Last Updated: December 2024 Audience: Frontend Developers
Overview
The platform uses Tailwind CSS for styling with a dual-layer architecture:
- Base Layer (CDN): Tailwind CSS v2.2.19 loaded via CDN with local fallback
- Override Layer (npm build): Custom Windmill Dashboard theme built from Tailwind v1.4.6
This layered approach allows:
- Fast loading via CDN for base utilities
- Custom theme extensions (colors, dark mode, forms) via npm build
- Offline support via local fallback
Note: A migration to Tailwind v3.4 is planned. See Migration Plan.
Architecture
How It Works
Browser loads:
1. CDN Tailwind 2.2.19 (base utilities)
└── Fallback: static/shared/css/tailwind.min.css
2. Custom tailwind.output.css (overrides/extensions)
└── Built from: static/admin/css/tailwind.css
└── Contains: Windmill Dashboard theme, custom colors, dark mode
Key Files
| File | Version | Purpose |
|---|---|---|
CDN tailwindcss@2.2.19 |
2.2.19 | Base Tailwind utilities |
static/shared/css/tailwind.min.css |
2.2.19 | Local fallback for CDN |
tailwind.config.js |
1.4.6 | Custom build configuration |
static/admin/css/tailwind.css |
- | Source file with directives |
static/admin/css/tailwind.output.css |
1.4.6 | Compiled custom styles |
static/vendor/css/tailwind.output.css |
1.4.6 | Compiled custom styles |
Template Loading Order
<!-- 1. Base Tailwind from CDN (with fallback) -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css"
onerror="this.onerror=null; this.href='/static/shared/css/tailwind.min.css';">
<!-- 2. Custom overrides (built via npm) -->
<link rel="stylesheet" href="/static/admin/css/tailwind.output.css" />
See CDN Fallback Strategy for details on offline support.
How Tailwind Purging Works
Tailwind generates thousands of utility classes. To keep the CSS file small, it "purges" (removes) unused classes by scanning your source files.
Content Paths
The purge.content array in tailwind.config.js tells Tailwind where to look for class usage:
purge: {
content: [
'public/**/*.html',
'app/templates/**/*.html', // Jinja2 templates
'static/**/*.js', // Alpine.js components
],
// ...
}
Safelist
Some classes are used dynamically in Alpine.js expressions and can't be detected by scanning. These must be added to the safelist:
purge: {
content: [...],
safelist: [
'bg-orange-600',
'bg-green-600',
'bg-red-600',
'hover:bg-orange-700',
'hover:bg-green-700',
'hover:bg-red-700',
],
}
When to add to safelist:
- Classes used in Alpine.js
:classbindings with dynamic conditions - Classes constructed from variables (e.g.,
bg-${color}-500) - Classes used only in JavaScript, not in HTML templates
Building Tailwind CSS
Prerequisites
Install Node.js dependencies (one-time setup):
npm install
Or using Make:
make npm-install
Development Build
For development, build without purging (includes all classes, larger file):
# Build admin CSS
npm run tailwind:admin
# Build vendor CSS
npm run tailwind:vendor
# Or using Make
make tailwind-dev
Production Build
For production, build with purging and minification (smaller file):
npm run build
# Or using Make
make tailwind-build
Available npm Scripts
| Script | Command | Description |
|---|---|---|
npm run tailwind:admin |
Build admin CSS (dev) | Fast, includes all classes |
npm run tailwind:vendor |
Build vendor CSS (dev) | Fast, includes all classes |
npm run build:admin |
Build admin CSS (prod) | Purged and minified |
npm run build:vendor |
Build vendor CSS (prod) | Purged and minified |
npm run build |
Build all (prod) | Runs both production builds |
Adding New Utility Classes
If you need a class that doesn't exist in the compiled CSS:
Option 1: Check if it's being purged
The class might exist but is being removed. Add it to the safelist in tailwind.config.js:
safelist: [
'your-new-class',
// ...
]
Option 2: Extend the theme
Add custom values to tailwind.config.js:
theme: {
extend: {
colors: {
'brand': '#123456',
},
spacing: {
'128': '32rem',
},
},
}
Option 3: Rebuild CSS
After any config change, rebuild the CSS:
make tailwind-dev
Troubleshooting
Classes not appearing
- Check purge paths - Ensure your file is in a scanned directory
- Check safelist - Dynamic classes need to be safelisted
- Rebuild CSS - Run
make tailwind-devafter config changes
Dynamic classes in Alpine.js
Problem: Classes in :class bindings may be purged.
<!-- This class might be purged -->
<div :class="isActive ? 'bg-green-600' : 'bg-red-600'">
Solution: Add to safelist:
safelist: ['bg-green-600', 'bg-red-600']
Large CSS file in development
Development builds include all Tailwind classes (~1.2MB). This is normal.
Production builds purge unused classes, resulting in much smaller files (~50-100KB typically).
Configuration Reference
tailwind.config.js Structure
module.exports = {
// Where to scan for class usage
purge: {
content: [...],
safelist: [...],
},
// Theme customization
theme: {
// Override defaults
colors: {...},
// Extend defaults
extend: {
fontFamily: {...},
maxHeight: {...},
},
},
// Variant configuration (hover, focus, dark mode, etc.)
variants: {
backgroundColor: ['hover', 'focus', 'dark', 'dark:hover'],
textColor: ['hover', 'dark'],
// ...
},
// Plugins
plugins: [
require('tailwindcss-multi-theme'),
require('@tailwindcss/custom-forms'),
],
}
Dark Mode
The platform uses tailwindcss-multi-theme for dark mode. Dark mode classes use the .theme-dark parent selector:
/* Light mode */
.bg-white { ... }
/* Dark mode */
.theme-dark .dark\:bg-gray-800 { ... }
Best Practices
-
Always rebuild after config changes
make tailwind-dev -
Add dynamic classes to safelist to prevent purging
-
Use production builds for deployment to minimize file size
-
Check existing classes first before adding custom ones - Tailwind likely has what you need
-
Use consistent color scales (e.g.,
purple-600,purple-700) for hover states