Episode 1 — Fundamentals / 1.11 — CSS Frameworks TailwindCSS and Bootstrap

1.11.c — TailwindCSS Setup & Basics

In one sentence: TailwindCSS is a utility-first CSS framework that lets you build designs directly in HTML by composing small, single-purpose classes — configured via a central file and compiled to ship only what you use.

Navigation: ← 1.11.b — Utility-First vs Component-Based · 1.11.d — Building with TailwindCSS →


1. What is TailwindCSS?

Tailwind is a utility-first CSS framework that provides thousands of low-level classes like flex, pt-4, text-center, and bg-blue-500. Instead of writing custom CSS, you compose these classes directly in your HTML.

Why it's popular:

  • No context-switching between HTML and CSS files
  • Production CSS is tiny — unused classes are automatically removed
  • A single config file controls the entire design system (colors, spacing, fonts, breakpoints)
  • Works with any frontend stack (React, Vue, Svelte, plain HTML)

2. Installation

Option A — Using the CLI (simplest)

npm install -D tailwindcss
npx tailwindcss init

This creates tailwind.config.js. Then add Tailwind directives to your CSS entry file:

/* src/input.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

Build with:

npx tailwindcss -i ./src/input.css -o ./dist/output.css --watch

Option B — With a bundler (Vite, Webpack, etc.)

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

The -p flag also creates postcss.config.js. Your bundler processes Tailwind through PostCSS automatically.

Configure content paths

Tell Tailwind where to scan for class names so it can purge unused styles:

// tailwind.config.js
module.exports = {
  content: [
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx,html}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
};

If a class appears nowhere in these files, it will not be in the production CSS.


3. Core concept: utility classes

Each utility class maps to one (or a small set of) CSS properties:

Utility classCSS it generates
flexdisplay: flex
items-centeralign-items: center
p-4padding: 1rem
mt-2margin-top: 0.5rem
text-lgfont-size: 1.125rem; line-height: 1.75rem
bg-blue-500background-color: #3b82f6
rounded-lgborder-radius: 0.5rem
shadow-mdbox-shadow: 0 4px 6px -1px rgba(0,0,0,.1), …
w-fullwidth: 100%
hiddendisplay: none

You compose them on elements:

<div class="flex items-center gap-4 p-4 bg-white rounded-lg shadow-md">
  <img class="w-12 h-12 rounded-full" src="avatar.jpg" alt="User" />
  <div>
    <p class="font-semibold text-gray-900">Jane Doe</p>
    <p class="text-sm text-gray-500">Developer</p>
  </div>
</div>

4. Responsive prefixes

Tailwind is mobile-first. Unprefixed utilities apply at all sizes. Prefixed utilities apply at that breakpoint and above:

PrefixMin-widthTypical device
sm:640pxLarge phones
md:768pxTablets
lg:1024pxLaptops
xl:1280pxDesktops
2xl:1536pxLarge screens
<!-- Stack on mobile, side-by-side on medium+ -->
<div class="flex flex-col md:flex-row gap-4">
  <div class="w-full md:w-1/2">Left</div>
  <div class="w-full md:w-1/2">Right</div>
</div>

Read this as: "column layout by default; at md (768px+), switch to row."


5. State variants

Apply styles conditionally based on element state:

VariantWhen it applies
hover:Mouse over element
focus:Element has focus
active:Element is being clicked
disabled:Element is disabled
first:First child
last:Last child
odd:Odd children
group-hover:Parent with group class is hovered
<button class="bg-blue-600 text-white px-4 py-2 rounded
               hover:bg-blue-700 focus:ring-2 focus:ring-blue-500
               active:bg-blue-800 disabled:opacity-50">
  Submit
</button>

Combine responsive + state: md:hover:bg-blue-700 — hover effect only on medium screens and above.


6. The spacing and color systems

Spacing scale (default)

Tailwind uses a consistent scale where 1 unit = 0.25rem (4px):

ClassValuePixels (at 16px root)
p-000px
p-10.25rem4px
p-20.5rem8px
p-41rem16px
p-61.5rem24px
p-82rem32px

Works with margins (m-), gaps (gap-), widths (w-), heights (h-), and more.

Color palette

Colors follow the pattern {property}-{color}-{shade}:

bg-red-500      →  background-color: red, medium shade
text-gray-700   →  color: dark gray
border-green-300 → border-color: light green

Shades range from 50 (lightest) to 950 (darkest).


7. The @apply directive

Extract repeated utility patterns into custom classes:

/* In your CSS file */
.btn-primary {
  @apply bg-blue-600 text-white font-semibold py-2 px-4 rounded-lg
         hover:bg-blue-700 focus:outline-none focus:ring-2
         focus:ring-blue-500 focus:ring-offset-2;
}
<!-- Now use a single class -->
<button class="btn-primary">Save</button>

Use sparingly. Overusing @apply recreates the problems Tailwind was designed to avoid — hidden styles and naming fatigue. Prefer component abstraction (React/Vue components) over @apply for reuse.


8. Customizing the config

// tailwind.config.js
module.exports = {
  content: ["./src/**/*.{html,js,jsx,tsx}"],
  theme: {
    extend: {
      colors: {
        brand: {
          50:  "#eff6ff",
          500: "#3b82f6",
          900: "#1e3a8a",
        },
      },
      fontFamily: {
        sans: ["Inter", "system-ui", "sans-serif"],
      },
      spacing: {
        18: "4.5rem",
      },
    },
  },
  plugins: [],
};

extend adds to defaults. Defining at the theme level (without extend) replaces defaults entirely. Use extend unless you intentionally want to remove default values.


9. Key takeaways

  1. Tailwind gives you utility classes — each does one CSS thing; you compose them in HTML.
  2. content paths in the config determine which files are scanned; unused classes are purged.
  3. Responsive prefixes (sm:, md:, lg:) are mobile-first — unprefixed = all sizes.
  4. State variants (hover:, focus:, active:) apply styles conditionally.
  5. @apply extracts repeated patterns into custom classes — use sparingly.
  6. Customize via tailwind.config.js — colors, fonts, spacing, breakpoints.

Explain-It Challenge

Explain without notes:

  1. What the content array in tailwind.config.js does and why it matters for production bundle size.
  2. How Tailwind's responsive prefixes work (what does md:flex mean?).
  3. When you should use @apply and when you should prefer a component abstraction instead.

Navigation: ← 1.11.b — Utility-First vs Component-Based · 1.11.d — Building with TailwindCSS →