Episode 1 — Fundamentals / 1.11 — CSS Frameworks TailwindCSS and Bootstrap
1.11.d — Building with TailwindCSS
In one sentence: Tailwind's real power shows when you build actual UI — layout with Flexbox/Grid utilities, responsive breakpoints, dark mode, and component extraction turn a bag of classes into production-ready interfaces.
Navigation: ← 1.11.c — TailwindCSS Setup & Basics · 1.11.e — Introduction to Bootstrap →
1. Layout with Flex and Grid
Tailwind wraps Flexbox and Grid into utility classes. If you understand the CSS concepts (see 1.10), the utilities are intuitive:
Flexbox
| Utility | CSS |
|---|---|
flex | display: flex |
flex-row | flex-direction: row (default) |
flex-col | flex-direction: column |
items-center | align-items: center |
justify-between | justify-content: space-between |
flex-wrap | flex-wrap: wrap |
flex-1 | flex: 1 1 0% (grow and shrink equally) |
gap-4 | gap: 1rem |
<!-- Horizontal nav with logo left, links right -->
<nav class="flex items-center justify-between px-6 py-4 bg-white shadow">
<a href="/" class="text-xl font-bold text-gray-900">Brand</a>
<div class="flex gap-6">
<a href="/about" class="text-gray-600 hover:text-gray-900">About</a>
<a href="/blog" class="text-gray-600 hover:text-gray-900">Blog</a>
<a href="/contact" class="text-gray-600 hover:text-gray-900">Contact</a>
</div>
</nav>
Grid
| Utility | CSS |
|---|---|
grid | display: grid |
grid-cols-3 | grid-template-columns: repeat(3, minmax(0, 1fr)) |
grid-cols-12 | grid-template-columns: repeat(12, minmax(0, 1fr)) |
col-span-4 | grid-column: span 4 / span 4 |
gap-6 | gap: 1.5rem |
<!-- 3-column grid of cards -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 p-6">
<div class="bg-white rounded-lg shadow p-6">Card 1</div>
<div class="bg-white rounded-lg shadow p-6">Card 2</div>
<div class="bg-white rounded-lg shadow p-6">Card 3</div>
</div>
2. Spacing: padding, margin, and gap
Tailwind's spacing utilities follow a consistent pattern:
{property}{side}-{size}
p-4 → padding: 1rem (all sides)
px-4 → padding-left + padding-right: 1rem
py-2 → padding-top + padding-bottom: 0.5rem
pt-6 → padding-top: 1.5rem
m-auto → margin: auto
-mt-4 → margin-top: -1rem (negative margin)
space-x-4 → gap between horizontal children (uses margin)
| Prefix | Sides |
|---|---|
p- / m- | All four sides |
px- / mx- | Left + Right (x-axis) |
py- / my- | Top + Bottom (y-axis) |
pt- / mt- | Top only |
pr- / mr- | Right only |
pb- / mb- | Bottom only |
pl- / ml- | Left only |
3. Colors and typography
Colors
<p class="text-gray-900">Dark text</p>
<p class="text-red-500">Error text</p>
<div class="bg-blue-100 border border-blue-300">Info box</div>
<button class="bg-green-600 hover:bg-green-700 text-white">Success</button>
Opacity modifier: bg-blue-500/75 → blue background at 75% opacity.
Typography
| Utility | Effect |
|---|---|
text-xs | 0.75rem |
text-sm | 0.875rem |
text-base | 1rem |
text-lg | 1.125rem |
text-xl | 1.25rem |
text-2xl | 1.5rem |
text-4xl | 2.25rem |
font-light | font-weight: 300 |
font-normal | font-weight: 400 |
font-semibold | font-weight: 600 |
font-bold | font-weight: 700 |
leading-tight | line-height: 1.25 |
tracking-wide | letter-spacing: 0.025em |
uppercase | text-transform: uppercase |
truncate | Truncate with ellipsis |
4. Responsive layouts
Tailwind is mobile-first: write base styles for mobile, then add styles at larger breakpoints.
<!--
Mobile: single column, small padding
Tablet (md): two columns
Desktop (lg): three columns, larger padding
-->
<div class="p-4 lg:p-8">
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 lg:gap-8">
<div class="p-4 bg-white rounded shadow">Feature 1</div>
<div class="p-4 bg-white rounded shadow">Feature 2</div>
<div class="p-4 bg-white rounded shadow">Feature 3</div>
</div>
</div>
Hiding/showing elements by breakpoint
<p class="block md:hidden">Mobile only</p>
<p class="hidden md:block">Desktop only</p>
5. Dark mode
Enable dark mode in your config, then use the dark: variant:
// tailwind.config.js
module.exports = {
darkMode: "class", // or "media" for OS preference
// ...
};
<!-- Toggles with a `dark` class on <html> or <body> -->
<div class="bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100 p-6">
<h2 class="text-xl font-bold">Dashboard</h2>
<p class="text-gray-600 dark:text-gray-400">Welcome back.</p>
</div>
darkMode value | How it activates |
|---|---|
"media" | Follows OS prefers-color-scheme automatically |
"class" | Requires adding class="dark" to a parent element (manual toggle) |
6. Example: responsive card component
<div class="max-w-sm mx-auto bg-white dark:bg-gray-800 rounded-xl
shadow-lg overflow-hidden">
<img class="w-full h-48 object-cover" src="mountain.jpg"
alt="Mountain landscape" />
<div class="p-6">
<div class="flex items-center gap-2 mb-3">
<span class="bg-green-100 text-green-800 text-xs font-medium
px-2.5 py-0.5 rounded dark:bg-green-900
dark:text-green-300">New</span>
<span class="text-sm text-gray-500 dark:text-gray-400">5 min read</span>
</div>
<h3 class="text-lg font-bold text-gray-900 dark:text-white mb-2">
Hiking the Alps
</h3>
<p class="text-gray-600 dark:text-gray-300 mb-4">
Discover the best trails across the Austrian Alps this summer.
</p>
<a href="#" class="inline-flex items-center text-blue-600
dark:text-blue-400 hover:underline font-medium">
Read more →
</a>
</div>
</div>
7. Example: responsive navbar
<nav class="bg-white dark:bg-gray-900 shadow">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex items-center justify-between h-16">
<!-- Logo -->
<a href="/" class="text-xl font-bold text-gray-900 dark:text-white">
MyApp
</a>
<!-- Desktop links (hidden on mobile) -->
<div class="hidden md:flex gap-8">
<a href="/features" class="text-gray-600 dark:text-gray-300
hover:text-gray-900 dark:hover:text-white">
Features</a>
<a href="/pricing" class="text-gray-600 dark:text-gray-300
hover:text-gray-900 dark:hover:text-white">
Pricing</a>
<a href="/docs" class="text-gray-600 dark:text-gray-300
hover:text-gray-900 dark:hover:text-white">
Docs</a>
</div>
<!-- CTA button -->
<a href="/signup" class="hidden md:inline-block bg-blue-600 text-white
px-4 py-2 rounded-lg hover:bg-blue-700">
Sign Up
</a>
<!-- Mobile menu button (visible on mobile only) -->
<button class="md:hidden text-gray-600 dark:text-gray-300">
<svg class="w-6 h-6" fill="none" stroke="currentColor"
viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round"
stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
</svg>
</button>
</div>
</div>
</nav>
8. Extracting reusable components
When patterns repeat, extract via framework components (React, Vue, etc.) — not @apply:
// React component — preferred reuse pattern
function Card({ title, description, image, badge }) {
return (
<div className="max-w-sm bg-white rounded-xl shadow-lg overflow-hidden">
<img className="w-full h-48 object-cover" src={image} alt={title} />
<div className="p-6">
{badge && (
<span className="bg-green-100 text-green-800 text-xs
font-medium px-2.5 py-0.5 rounded">{badge}</span>
)}
<h3 className="text-lg font-bold mt-2">{title}</h3>
<p className="text-gray-600 mt-2">{description}</p>
</div>
</div>
);
}
When @apply is appropriate: global styles that can't be components — e.g., .prose overrides, third-party widget styling, or base element resets.
9. Key takeaways
- Use
flexandgridutilities for layout — they mirror the CSS properties you already know. - Spacing follows a consistent scale (
p-4= 1rem,p-8= 2rem) for visual rhythm. - Responsive design = mobile-first base + breakpoint prefixes (
md:,lg:). - Dark mode uses the
dark:variant — toggle via OS preference or manual class. - Extract components via your framework (React, Vue), not
@apply, for reuse.
Explain-It Challenge
Explain without notes:
- How Tailwind's mobile-first responsive approach works (what does an unprefixed class do vs a prefixed one?).
- The difference between
darkMode: "media"anddarkMode: "class"intailwind.config.js. - Why you should prefer framework components (React, Vue) over
@applyfor reusing Tailwind patterns.
Navigation: ← 1.11.c — TailwindCSS Setup & Basics · 1.11.e — Introduction to Bootstrap →