Why I switched to Tailwind CSS
Built websites for 8 years with vanilla CSS, Bootstrap, you name it. Every project ended up the same: thousands of lines of custom CSS, class names like card-header-primary-button, and responsive designs that broke on someone's phone.
Hated it. Spent more time fighting CSS specificity than building features. Naming classes gave me anxiety. "Is this btn or button or btn-primary?" Don't get me started on BEM methodology.
Then tried Tailwind CSS. Skeptical at first - utility classes felt weird. But after one project, I was hooked. No more custom CSS files. No more naming classes. Just HTML with class names that describe what stuff looks like.
My layouts became responsive by default. Spacing was consistent. Design system emerged organically. Best part: the CSS file stayed tiny because unused styles get purged in production.
What Tailwind actually is
Utility-first CSS framework. Instead of writing custom CSS in separate files, you use pre-defined classes directly in HTML. flex for flexbox, p-4 for padding, text-center for centered text. Build complex designs without writing CSS.
Installation and setup
Quickest way to start with Tailwind CSS.
Option 1: CDN (for prototyping)
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body>
<h1 class="text-3xl font-bold text-blue-600">Hello Tailwind!</h1>
</body>
</html>
Fastest way to try Tailwind. Not recommended for production (large file size).
Option 2: npm (for production)
# Create project
mkdir my-tailwind-project
cd my-tailwind-project
npm init -y
# Install Tailwind CSS
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
Configure Tailwind
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./src/**/*.{html,js}",
"./public/**/*.html",
],
theme: {
extend: {},
},
plugins: [],
}
Add Tailwind directives
/* src/input.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
Build CSS
# Build CSS file
npx tailwindcss -i ./src/input.css -o ./dist/output.css --watch
# Or add to package.json scripts
"scripts": {
"build": "tailwindcss -i ./src/input.css -o ./dist/output.css",
"watch": "tailwindcss -i ./src/input.css -o ./dist/output.css --watch"
}
Fundamental concepts
Tailwind basics you'll use every day.
1. Spacing scale
Tailwind uses a consistent spacing scale. Goodbye random numbers.
<!-- Padding -->
<div class="p-4">Padding: 1rem (16px)</div>
<div class="px-6 py-2">Padding X: 1.5rem, Padding Y: 0.5rem</div>
<!-- Margin -->
<div class="m-4">Margin: 1rem</div>
<div class="mt-8 mb-4">Margin Top: 2rem, Margin Bottom: 1rem</div>
<!-- Scale reference -->
<!-- 0: 0px, 1: 0.25rem (4px), 2: 0.5rem (8px), 3: 0.75rem (12px)
4: 1rem (16px), 5: 1.25rem (20px), 6: 1.5rem (24px), 8: 2rem (32px) -->
2. Flexbox layouts
<!-- Horizontal centering -->
<div class="flex justify-center">
<span>Centered</span>
</div>
<!-- Space between items -->
<div class="flex justify-between items-center p-4">
<span>Left</span>
<span>Right</span>
</div>
<!-- Column layout -->
<div class="flex flex-col gap-4">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</div>
3. Grid layouts
<!-- 3 column grid -->
<div class="grid grid-cols-3 gap-4">
<div>Column 1</div>
<div>Column 2</div>
<div>Column 3</div>
</div>
<!-- Responsive grid -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<!-- 1 column on mobile, 2 on tablet, 3 on desktop -->
<div>Responsive</div>
</div>
<!-- Grid with spanning -->
<div class="grid grid-cols-4 gap-4">
<div class="col-span-2">Spans 2 columns</div>
<div class="col-span-1">1 column</div>
<div class="col-span-1">1 column</div>
</div>
4. Colors and typography
<!-- Colors -->
<div class="bg-blue-500 text-white">Blue background, white text</div>
<div class="bg-red-100 border border-red-500">Light red bg, red border</div>
<!-- Typography -->
<h1 class="text-4xl font-bold">Large bold heading</h1>
<p class="text-lg text-gray-600">Large text, gray color</p>
<p class="text-sm font-light">Small light text</p>
<!-- Text alignment -->
<p class="text-center">Centered text</p>
<p class="text-right">Right-aligned text</p>
Responsive design made easy
This is where Tailwind shines. Mobile-first responsive design.
Breakpoint system
Tailwind uses mobile-first breakpoints.
sm: 640px # Small tablets
md: 768px # Tablets
lg: 1024px # Laptops
xl: 1280px # Desktops
2xl: 1536px # Large screens
Pattern 1: Responsive grid
Grid that adapts to screen size automatically.
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
<!-- Mobile: 1 column, Tablet: 2 columns, Desktop: 4 columns -->
<div class="bg-white p-6 rounded-lg shadow">Card 1</div>
<div class="bg-white p-6 rounded-lg shadow">Card 2</div>
<div class="bg-white p-6 rounded-lg shadow">Card 3</div>
<div class="bg-white p-6 rounded-lg shadow">Card 4</div>
</div>
Pattern 2: Responsive navigation
Hamburger menu on mobile, full menu on desktop.
<nav class="flex justify-between items-center p-4">
<div class="text-xl font-bold">Logo</div>
<!-- Mobile: hidden, Desktop: visible -->
<div class="hidden md:flex space-x-4">
<a href="#" class="hover:text-blue-600">Home</a>
<a href="#" class="hover:text-blue-600">About</a>
<a href="#" class="hover:text-blue-600">Contact</a>
</div>
<!-- Mobile: visible, Desktop: hidden -->
<button class="md:hidden">☰</button>
</nav>
Pattern 3: Responsive spacing
More padding on larger screens.
<div class="p-4 md:p-8 lg:p-12">
<h1 class="text-2xl md:text-4xl">
Larger padding and text on desktop
</h1>
</div>
<!-- Different spacing on mobile vs desktop -->
<section class="px-4 py-8 md:px-8 md:py-16">
Content
</section>
Pattern 4: Hidden elements
Show/hide content based on screen size.
<!-- Only show on mobile -->
<div class="block md:hidden">
Mobile-only content
</div>
<!-- Only show on desktop -->
<div class="hidden md:block">
Desktop-only content
</div>
<!-- Hide on small screens, show on large -->
<div class="hidden lg:block">
Large screens only
</div>
Common layout patterns
Real layouts I use in every project.
1. Card layout
<div class="max-w-md mx-auto bg-white rounded-xl shadow-md overflow-hidden">
<img src="image.jpg" alt="Card image" class="w-full h-48 object-cover">
<div class="p-6">
<h2 class="text-2xl font-bold mb-2">Card Title</h2>
<p class="text-gray-600 mb-4">Card description goes here.</p>
<button class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600">
Action
</button>
</div>
</div>
2. Hero section
<section class="bg-gradient-to-r from-blue-600 to-purple-600 text-white py-20">
<div class="container mx-auto px-4 text-center">
<h1 class="text-4xl md:text-6xl font-bold mb-6">
Hero Title
</h1>
<p class="text-xl md:text-2xl mb-8 opacity-90">
Hero description text
</p>
<div class="flex flex-col md:flex-row gap-4 justify-center">
<button class="bg-white text-blue-600 px-8 py-3 rounded-lg font-bold">
Primary CTA
</button>
<button class="border-2 border-white px-8 py-3 rounded-lg font-bold">
Secondary CTA
</button>
</div>
</div>
</section>
3. Dashboard layout
<div class="flex min-h-screen">
<!-- Sidebar -->
<aside class="w-64 bg-gray-800 text-white hidden md:block">
<div class="p-4">
<h2 class="text-xl font-bold">Dashboard</h2>
</div>
<nav class="mt-8">
<a href="#" class="block px-4 py-2 hover:bg-gray-700">Overview</a>
<a href="#" class="block px-4 py-2 hover:bg-gray-700">Analytics</a>
<a href="#" class="block px-4 py-2 hover:bg-gray-700">Settings</a>
</nav>
</aside>
<!-- Main content -->
<main class="flex-1 bg-gray-100">
<header class="bg-white shadow p-4">
<h1 class="text-2xl font-bold">Page Title</h1>
</header>
<div class="p-6">
Content goes here
</div>
</main>
</div>
4. Feature grid
<section class="py-16">
<div class="container mx-auto px-4">
<h2 class="text-3xl font-bold text-center mb-12">Features</h2>
<div class="grid grid-cols-1 md:grid-cols-3 gap-8">
<!-- Feature 1 -->
<div class="text-center">
<div class="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4">
<span class="text-2xl">🚀</span>
</div>
<h3 class="text-xl font-bold mb-2">Feature 1</h3>
<p class="text-gray-600">Description of feature 1</p>
</div>
<!-- Feature 2 -->
<div class="text-center">
<div class="w-16 h-16 bg-green-100 rounded-full flex items-center justify-center mx-auto mb-4">
<span class="text-2xl">⚡</span>
</div>
<h3 class="text-xl font-bold mb-2">Feature 2</h3>
<p class="text-gray-600">Description of feature 2</p>
</div>
<!-- Feature 3 -->
<div class="text-center">
<div class="w-16 h-16 bg-purple-100 rounded-full flex items-center justify-center mx-auto mb-4">
<span class="text-2xl">🎯</span>
</div>
<h3 class="text-xl font-bold mb-2">Feature 3</h3>
<p class="text-gray-600">Description of feature 3</p>
</div>
</div>
</div>
</section>
Building components
Reusable UI components with Tailwind.
Button component
<!-- Primary button -->
<button class="bg-blue-500 text-white px-6 py-2 rounded-lg hover:bg-blue-600 transition">
Primary
</button>
<!-- Secondary button -->
<button class="bg-gray-200 text-gray-800 px-6 py-2 rounded-lg hover:bg-gray-300 transition">
Secondary
</button>
<!-- Outline button -->
<button class="border-2 border-blue-500 text-blue-500 px-6 py-2 rounded-lg hover:bg-blue-50 transition">
Outline
</button>
<!-- Full width button -->
<button class="w-full bg-blue-500 text-white py-3 rounded-lg hover:bg-blue-600 transition">
Full Width
</button>
Form inputs
<form class="max-w-md mx-auto space-y-4">
<div>
<label class="block text-sm font-medium mb-2">Email</label>
<input
type="email"
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
placeholder="you@example.com"
>
</div>
<div>
<label class="block text-sm font-medium mb-2">Message</label>
<textarea
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
rows="4"
placeholder="Your message"
></textarea>
</div>
<button
type="submit"
class="w-full bg-blue-500 text-white py-2 rounded-lg hover:bg-blue-600 transition"
>
Submit
</button>
</form>
Customization and theming
Tailwind is highly customizable. Don't fight defaults.
Custom colors
// tailwind.config.js
module.exports = {
theme: {
extend: {
colors: {
brand: {
50: '#f0f9ff',
100: '#e0f2fe',
500: '#0ea5e9',
600: '#0284c7',
900: '#0c4a6e',
}
}
}
}
}
// Use in HTML
<div class="bg-brand-500 text-white">Custom brand color</div>
Custom spacing
// tailwind.config.js
module.exports = {
theme: {
extend: {
spacing: {
'128': '32rem',
'144': '36rem',
}
}
}
}
// Use in HTML
<div class="p-128">Custom padding</div>
Custom breakpoints
// tailwind.config.js
module.exports = {
theme: {
extend: {
screens: {
'3xl': '1600px',
}
}
}
}
// Use in HTML
<div class="3xl:text-6xl">Extra large text</div>
Performance best practices
Keep your CSS bundle small.
1. Purge unused styles
// tailwind.config.js
module.exports = {
content: [
"./src/**/*.{html,js}",
"./public/**/*.html",
],
// Tailwind automatically scans these files and removes unused CSS
}
2. Avoid dynamic class names
<!-- Bad: Tailwind can't detect these -->
<div class="bg-{{ color }}-500"></div>
<!-- Good: Use complete classes -->
<div class="bg-blue-500"></div>
<div class="bg-red-500"></div>
3. Use JIT mode
// tailwind.config.js
module.exports = {
mode: 'jit',
// Generates styles on-demand, smaller bundles
}
Tailwind vs other approaches
Quick comparison.
| Aspect | Tailwind CSS | Vanilla CSS | Bootstrap |
|---|---|---|---|
| Learning curve | Moderate | Low | Low |
| Development speed | Fast | Slow | Fast |
| Bundle size | Small (purged) | Depends | Medium |
| Customization | High | Unlimited | Moderate |
| Consistency | High | Low | High |
Common issues and fixes
Stuff that breaks and how to fix it.
Issue: Styles not applying
Fix: Make sure you imported Tailwind directives in your CSS. Check that content paths in tailwind.config.js include your HTML files. Try rebuilding CSS.
Issue: Responsive classes not working
Fix: Remember mobile-first approach. Base classes apply to all screens, breakpoint classes apply to that size and up. Don't use max-width media queries mentally.
Issue: Large CSS file in production
Fix: Enable JIT mode or configure purge correctly. Check that content paths are correct. Run build command with --minify flag.
Issue: Custom config not working
Fix: Restart dev server after editing tailwind.config.js. Clear build cache. Ensure syntax is valid JavaScript.
Tips for faster development
Hard-earned lessons.
1. Learn the spacing scale
Memorize 4, 8, 12, 16. You'll use them constantly. gap-4, p-8, m-12.
2. Use VS Code extension
Install "Tailwind CSS IntelliSense". Autocomplete, class descriptions, preview on hover. Game changer.
3. Create reusable components
Don't repeat classes. Create React components or partials with common Tailwind patterns.
4. Use arbitrary values sparingly
w-[500px] is fine for one-offs. But prefer scale values for consistency.
5. Mobile-first mindset
Start with mobile layout. Add md:, lg: breakpoints later. Prevents desktop-first thinking.
6. Read the docs
Tailwind docs are excellent. Bookmark the search page. You'll discover utilities you didn't know existed.
Bottom line
Tailwind CSS isn't magic. It's just a different approach to writing CSS. But that approach saves me hours every week.
No more CSS files to maintain. No more naming classes. No more fighting specificity. Just HTML that describes what stuff looks like.
Responsive design became trivial. Design systems emerged naturally. My CSS bundles stayed small because unused styles get purged automatically.
Give it a shot on your next project. Start with CDN to try it out. If it clicks, switch to npm for production. Worst case: you learn a new tool. Best case: you never write custom CSS again.