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

UtilityCSS
flexdisplay: flex
flex-rowflex-direction: row (default)
flex-colflex-direction: column
items-centeralign-items: center
justify-betweenjustify-content: space-between
flex-wrapflex-wrap: wrap
flex-1flex: 1 1 0% (grow and shrink equally)
gap-4gap: 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

UtilityCSS
griddisplay: grid
grid-cols-3grid-template-columns: repeat(3, minmax(0, 1fr))
grid-cols-12grid-template-columns: repeat(12, minmax(0, 1fr))
col-span-4grid-column: span 4 / span 4
gap-6gap: 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)
PrefixSides
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

UtilityEffect
text-xs0.75rem
text-sm0.875rem
text-base1rem
text-lg1.125rem
text-xl1.25rem
text-2xl1.5rem
text-4xl2.25rem
font-lightfont-weight: 300
font-normalfont-weight: 400
font-semiboldfont-weight: 600
font-boldfont-weight: 700
leading-tightline-height: 1.25
tracking-wideletter-spacing: 0.025em
uppercasetext-transform: uppercase
truncateTruncate 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 valueHow 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

  1. Use flex and grid utilities for layout — they mirror the CSS properties you already know.
  2. Spacing follows a consistent scale (p-4 = 1rem, p-8 = 2rem) for visual rhythm.
  3. Responsive design = mobile-first base + breakpoint prefixes (md:, lg:).
  4. Dark mode uses the dark: variant — toggle via OS preference or manual class.
  5. Extract components via your framework (React, Vue), not @apply, for reuse.

Explain-It Challenge

Explain without notes:

  1. How Tailwind's mobile-first responsive approach works (what does an unprefixed class do vs a prefixed one?).
  2. The difference between darkMode: "media" and darkMode: "class" in tailwind.config.js.
  3. Why you should prefer framework components (React, Vue) over @apply for reusing Tailwind patterns.

Navigation: ← 1.11.c — TailwindCSS Setup & Basics · 1.11.e — Introduction to Bootstrap →