Toolmingo
Guides22 min read

Tailwind CSS Tutorial for Beginners (2025) — Learn Tailwind Step by Step

Complete Tailwind CSS tutorial for beginners. Learn Tailwind CSS from scratch: utility classes, responsive design, dark mode, components, and build 3 real projects.

Tailwind CSS Tutorial for Beginners (2025)

Tailwind CSS is a utility-first CSS framework that lets you build any design directly in your HTML. Instead of writing custom CSS, you compose pre-built utility classes.

This tutorial takes you from zero to building production-ready UIs with Tailwind CSS 3.x.

Why Learn Tailwind CSS?

Reason Detail
No context switching Style in HTML, no separate CSS files
No naming No inventing class names like .card-header-inner-wrapper
Fast iteration Change styles without touching CSS files
Responsive built-in md:flex lg:grid prefixes for breakpoints
Dark mode built-in dark:bg-gray-900 without custom media queries
Tiny production bundle Purges unused classes — typically < 10KB
Highly adoptable Works with React, Vue, Angular, plain HTML
Job market Used by Vercel, GitHub, OpenAI, Shopify

Tailwind vs Bootstrap vs Custom CSS

Feature Tailwind CSS Bootstrap Custom CSS
Approach Utility-first Component-first Write-your-own
Bundle size (dev) Large (all classes) ~150KB Varies
Bundle size (prod) < 10KB (purged) ~30KB Varies
Design uniqueness Unique — no default look Bootstrap look Fully custom
Learning curve Medium Low High
Customization Deep (tailwind.config.js) Limited overrides Unlimited
Responsive sm:, md:, lg:, xl:, 2xl: Grid + breakpoints Media queries
Dark mode dark: prefix Limited prefers-color-scheme
Component library shadcn/ui, Headless UI Built-in components DIY
Maintenance Rename class in HTML Override specificity Stylesheet debt

Setup

Option 1: CDN (For Learning / Prototyping)

No install needed:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Tailwind CSS</title>
  <script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-gray-100 p-8">
  <h1 class="text-3xl font-bold text-blue-600">Hello, Tailwind!</h1>
  <p class="mt-4 text-gray-700">This is Tailwind CSS via CDN.</p>
</body>
</html>

CDN is great for learning, but NOT for production — it loads all classes (3MB+). Use the CLI for real projects.

Option 2: Tailwind CLI (Recommended for HTML projects)

# Install Tailwind
npm install -D tailwindcss
npx tailwindcss init

# Input CSS (src/input.css)
# Output CSS (dist/output.css)
npx tailwindcss -i ./src/input.css -o ./dist/output.css --watch

Your src/input.css:

@tailwind base;
@tailwind components;
@tailwind utilities;

Your tailwind.config.js:

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ["./src/**/*.{html,js}"],
  theme: {
    extend: {},
  },
  plugins: [],
}

Option 3: Vite + React (Most Common in 2025)

npm create vite@latest my-app -- --template react
cd my-app
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

Update tailwind.config.js:

/** @type {import('tailwindcss').Config} */
export default {
  content: [
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

Add to src/index.css:

@tailwind base;
@tailwind components;
@tailwind utilities;

Import in src/main.jsx:

import './index.css'

Run:

npm run dev

Option 4: Next.js

npx create-next-app@latest my-app --tailwind
# Tailwind is automatically configured

Project Structure

my-app/
├── src/
│   ├── index.css          # Tailwind directives
│   ├── main.jsx
│   └── App.jsx
├── tailwind.config.js     # Tailwind configuration
├── postcss.config.js      # PostCSS (Vite sets this up)
└── package.json

Core Concepts

Utility Classes — The Tailwind Way

Instead of writing CSS, you apply utility classes directly in HTML:

<!-- Traditional CSS -->
<style>
  .card {
    background-color: white;
    border-radius: 8px;
    box-shadow: 0 1px 3px rgba(0,0,0,0.12);
    padding: 24px;
    max-width: 320px;
  }
</style>
<div class="card">...</div>

<!-- Tailwind Way -->
<div class="bg-white rounded-lg shadow p-6 max-w-sm">...</div>

The Tailwind Mental Model

Every Tailwind class maps to one or a few CSS properties:

Utility CSS
text-blue-600 color: rgb(37 99 235)
bg-gray-100 background-color: rgb(243 244 246)
p-4 padding: 1rem
flex display: flex
rounded-lg border-radius: 0.5rem
shadow box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)
font-bold font-weight: 700
w-full width: 100%
hidden display: none
uppercase text-transform: uppercase

Spacing

Tailwind uses a spacing scale. 1 unit = 0.25rem = 4px (default).

Padding

<div class="p-4">16px all sides</div>
<div class="px-4">16px left + right (x-axis)</div>
<div class="py-4">16px top + bottom (y-axis)</div>
<div class="pt-2 pr-4 pb-2 pl-4">individual sides</div>
<div class="ps-4">padding-inline-start (RTL aware)</div>

Margin

<div class="m-4">16px all sides</div>
<div class="mx-auto">center horizontally</div>
<div class="mt-8 mb-4">top 32px, bottom 16px</div>
<div class="-mt-2">negative margin (pull up 8px)</div>

Spacing Scale

Class Value
0 0px
0.5 2px
1 4px
2 8px
3 12px
4 16px
5 20px
6 24px
8 32px
10 40px
12 48px
16 64px
20 80px
24 96px
32 128px
px 1px

Typography

Font Size

<p class="text-xs">12px</p>
<p class="text-sm">14px</p>
<p class="text-base">16px (default)</p>
<p class="text-lg">18px</p>
<p class="text-xl">20px</p>
<p class="text-2xl">24px</p>
<p class="text-3xl">30px</p>
<p class="text-4xl">36px</p>
<p class="text-5xl">48px</p>
<p class="text-6xl">60px</p>

Font Weight

<p class="font-thin">100</p>
<p class="font-light">300</p>
<p class="font-normal">400</p>
<p class="font-medium">500</p>
<p class="font-semibold">600</p>
<p class="font-bold">700</p>
<p class="font-extrabold">800</p>
<p class="font-black">900</p>

Text Color

<p class="text-gray-900">near black</p>
<p class="text-gray-600">medium gray</p>
<p class="text-gray-400">light gray</p>
<p class="text-blue-600">blue</p>
<p class="text-red-500">red</p>
<p class="text-green-600">green</p>
<p class="text-white">white</p>

Other Typography

<p class="leading-tight">line-height: 1.25</p>
<p class="leading-normal">line-height: 1.5</p>
<p class="leading-loose">line-height: 2</p>
<p class="tracking-tight">letter-spacing: -0.05em</p>
<p class="tracking-wide">letter-spacing: 0.025em</p>
<p class="italic">italic</p>
<p class="underline">underlined</p>
<p class="line-through">strikethrough</p>
<p class="uppercase">UPPERCASE</p>
<p class="capitalize">Capitalize First</p>
<p class="truncate">Long text that gets truncated...</p>
<p class="text-center">centered</p>
<p class="text-right">right-aligned</p>

Colors

Tailwind includes a full color palette. Colors come in shades 50–950.

<!-- Slate -->
<div class="bg-slate-100">Light slate</div>
<div class="bg-slate-800">Dark slate</div>

<!-- Blue -->
<div class="bg-blue-50">Lightest blue</div>
<div class="bg-blue-500">Medium blue</div>
<div class="bg-blue-900">Darkest blue</div>

<!-- All color families: -->
<!-- slate, gray, zinc, neutral, stone -->
<!-- red, orange, amber, yellow, lime -->
<!-- green, emerald, teal, cyan -->
<!-- sky, blue, indigo, violet, purple, fuchsia, pink, rose -->

Opacity Modifier

<div class="bg-blue-500/50">50% opacity blue background</div>
<p class="text-black/75">75% opacity black text</p>

Backgrounds

<div class="bg-white">white</div>
<div class="bg-transparent">transparent</div>
<div class="bg-gradient-to-r from-blue-500 to-purple-600">gradient</div>
<div class="bg-cover bg-center" style="background-image: url(...)">image</div>

Borders

<div class="border">1px border (default color)</div>
<div class="border-2">2px border</div>
<div class="border-4">4px border</div>
<div class="border-blue-500">colored border</div>
<div class="border-dashed">dashed</div>
<div class="border-dotted">dotted</div>
<div class="border-t">top border only</div>
<div class="border-b-2 border-blue-600">bottom border 2px blue</div>

<!-- Border radius -->
<div class="rounded">4px radius</div>
<div class="rounded-md">6px radius</div>
<div class="rounded-lg">8px radius</div>
<div class="rounded-xl">12px radius</div>
<div class="rounded-2xl">16px radius</div>
<div class="rounded-full">50% (pill/circle)</div>
<div class="rounded-t-lg">only top rounded</div>

Sizing

Width

<div class="w-4">16px (1rem)</div>
<div class="w-16">64px (4rem)</div>
<div class="w-64">256px (16rem)</div>
<div class="w-full">100%</div>
<div class="w-screen">100vw</div>
<div class="w-1/2">50%</div>
<div class="w-1/3">33.333%</div>
<div class="w-2/3">66.666%</div>
<div class="w-auto">auto</div>
<div class="min-w-0">min-width: 0</div>
<div class="max-w-xs">max-width: 320px</div>
<div class="max-w-sm">max-width: 384px</div>
<div class="max-w-md">max-width: 448px</div>
<div class="max-w-lg">max-width: 512px</div>
<div class="max-w-xl">max-width: 576px</div>
<div class="max-w-2xl">max-width: 672px</div>
<div class="max-w-4xl">max-width: 896px</div>
<div class="max-w-7xl">max-width: 1280px</div>

Height

<div class="h-16">64px</div>
<div class="h-full">100%</div>
<div class="h-screen">100vh</div>
<div class="h-svh">100svh (safe viewport)</div>
<div class="min-h-screen">min-height: 100vh</div>

Display & Layout

<div class="block">block</div>
<span class="inline-block">inline-block</span>
<div class="hidden">display: none</div>
<div class="flex">flex container</div>
<div class="grid">grid container</div>
<div class="inline-flex">inline flex</div>

Flexbox

<!-- Flex container -->
<div class="flex">
  <!-- defaults: row, no-wrap, stretch -->
</div>

<!-- Direction -->
<div class="flex flex-row">horizontal (default)</div>
<div class="flex flex-col">vertical</div>
<div class="flex flex-row-reverse">reverse horizontal</div>
<div class="flex flex-col-reverse">reverse vertical</div>

<!-- Wrap -->
<div class="flex flex-wrap">wrap items</div>
<div class="flex flex-nowrap">no wrap (default)</div>

<!-- Justify (main axis) -->
<div class="flex justify-start">start (default)</div>
<div class="flex justify-center">center</div>
<div class="flex justify-end">end</div>
<div class="flex justify-between">space-between</div>
<div class="flex justify-around">space-around</div>
<div class="flex justify-evenly">space-evenly</div>

<!-- Align (cross axis) -->
<div class="flex items-start">top</div>
<div class="flex items-center">center</div>
<div class="flex items-end">bottom</div>
<div class="flex items-stretch">stretch (default)</div>
<div class="flex items-baseline">baseline</div>

<!-- Gap -->
<div class="flex gap-4">16px gap between items</div>
<div class="flex gap-x-4 gap-y-2">separate x and y gaps</div>

<!-- Flex items -->
<div class="flex-1">flex: 1 1 0% (grow and shrink)</div>
<div class="flex-auto">flex: 1 1 auto</div>
<div class="flex-none">flex: none (no grow/shrink)</div>
<div class="grow">flex-grow: 1</div>
<div class="shrink-0">flex-shrink: 0</div>

Common Flex Patterns

<!-- Center horizontally and vertically -->
<div class="flex items-center justify-center h-screen">
  <p>Perfectly centered</p>
</div>

<!-- Navbar: logo left, links right -->
<nav class="flex items-center justify-between p-4">
  <div class="text-xl font-bold">Logo</div>
  <ul class="flex gap-6">
    <li><a href="#">Home</a></li>
    <li><a href="#">About</a></li>
    <li><a href="#">Contact</a></li>
  </ul>
</nav>

<!-- Equal width columns -->
<div class="flex gap-4">
  <div class="flex-1 bg-blue-100 p-4">Column 1</div>
  <div class="flex-1 bg-green-100 p-4">Column 2</div>
  <div class="flex-1 bg-red-100 p-4">Column 3</div>
</div>

<!-- Sidebar + Content layout -->
<div class="flex h-screen">
  <aside class="w-64 bg-gray-800 text-white p-4">Sidebar</aside>
  <main class="flex-1 p-4 overflow-auto">Main Content</main>
</div>

CSS Grid

<!-- Basic grid -->
<div class="grid grid-cols-3 gap-4">
  <div>Item 1</div>
  <div>Item 2</div>
  <div>Item 3</div>
</div>

<!-- Auto-fit responsive grid -->
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
  <!-- columns adapt to screen size -->
</div>

<!-- Span columns -->
<div class="grid grid-cols-3 gap-4">
  <div class="col-span-2">Takes 2 columns</div>
  <div>1 column</div>
</div>

<!-- Span rows -->
<div class="grid grid-cols-2 grid-rows-2 gap-4">
  <div class="row-span-2">Tall item</div>
  <div>Item 2</div>
  <div>Item 3</div>
</div>

<!-- Grid template areas -->
<div class="grid grid-cols-[200px_1fr] grid-rows-[auto_1fr_auto] min-h-screen">
  <!-- Arbitrary values with [] -->
</div>

Grid vs Flexbox

Use case Tool
1D layout (row OR column) Flexbox
2D layout (rows AND columns) Grid
Navigation bar Flexbox
Card grid Grid
Centering content Either
Magazine layout Grid
Component internals Flexbox
Overall page layout Grid

Responsive Design

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

Breakpoints

Prefix Min width Common use
(none) 0px Mobile (base)
sm: 640px Small tablets
md: 768px Tablets
lg: 1024px Laptops
xl: 1280px Desktops
2xl: 1536px Large screens
<!-- Hidden on mobile, block on medium+ -->
<div class="hidden md:block">
  Desktop content
</div>

<!-- Full width on mobile, half on medium, third on large -->
<div class="w-full md:w-1/2 lg:w-1/3">...</div>

<!-- Stack on mobile, row on desktop -->
<div class="flex flex-col md:flex-row gap-4">
  <div>Column A</div>
  <div>Column B</div>
</div>

<!-- Font size grows with screen -->
<h1 class="text-2xl md:text-4xl lg:text-6xl font-bold">
  Responsive Heading
</h1>

<!-- Grid responsive -->
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
  <div>Card</div>
  <div>Card</div>
  <div>Card</div>
  <div>Card</div>
</div>

Dark Mode

Enable in tailwind.config.js:

export default {
  darkMode: 'class', // or 'media'
  // ...
}
  • 'media' — uses prefers-color-scheme OS setting
  • 'class' — toggle dark class on <html> (gives you control)
<!-- With class strategy: add 'dark' class to <html> -->
<html class="dark">

<!-- Dark variants -->
<div class="bg-white dark:bg-gray-900 text-gray-900 dark:text-white p-6">
  <h1 class="text-2xl font-bold text-gray-900 dark:text-white">
    Adapts to dark mode
  </h1>
  <p class="text-gray-600 dark:text-gray-400">
    Subtle text that lightens in dark mode
  </p>
  <button class="bg-blue-600 dark:bg-blue-500 text-white px-4 py-2 rounded">
    Button
  </button>
</div>

Toggle dark mode with JS:

// Toggle
document.documentElement.classList.toggle('dark')

// React example
const [dark, setDark] = useState(false)
useEffect(() => {
  document.documentElement.classList.toggle('dark', dark)
}, [dark])

Hover, Focus, and State Variants

<!-- Hover -->
<button class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded">
  Hover me
</button>

<!-- Focus -->
<input class="border border-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 p-2 rounded" />

<!-- Active -->
<button class="bg-blue-600 active:bg-blue-800 text-white px-4 py-2 rounded">
  Click me
</button>

<!-- Disabled -->
<button class="bg-blue-600 disabled:opacity-50 disabled:cursor-not-allowed text-white px-4 py-2 rounded" disabled>
  Disabled
</button>

<!-- Group hover (parent hover affects child) -->
<div class="group p-4 bg-gray-100 hover:bg-blue-600 rounded">
  <p class="text-gray-900 group-hover:text-white">
    I change when parent is hovered
  </p>
</div>

<!-- Peer (sibling state) -->
<input class="peer border p-2 rounded" placeholder="Type..." />
<p class="hidden peer-focus:block text-sm text-blue-600">
  Now typing...
</p>

<!-- First/last child -->
<ul>
  <li class="border-b last:border-b-0 py-2">Item 1</li>
  <li class="border-b last:border-b-0 py-2">Item 2</li>
  <li class="border-b last:border-b-0 py-2">Item 3</li>
</ul>

<!-- Odd/even -->
<tr class="bg-white odd:bg-gray-50">...</tr>

Shadows and Effects

<!-- Box shadow -->
<div class="shadow-sm">Small shadow</div>
<div class="shadow">Default shadow</div>
<div class="shadow-md">Medium shadow</div>
<div class="shadow-lg">Large shadow</div>
<div class="shadow-xl">Extra large</div>
<div class="shadow-2xl">2x large</div>
<div class="shadow-inner">Inner shadow</div>
<div class="shadow-none">No shadow</div>
<div class="shadow-blue-500/50">Colored shadow (with opacity)</div>

<!-- Opacity -->
<div class="opacity-50">50% transparent</div>
<div class="opacity-0">invisible (but takes space)</div>

<!-- Blur -->
<div class="blur">blurred</div>
<div class="blur-sm">small blur</div>
<div class="blur-md">medium blur</div>
<div class="backdrop-blur-sm">blur the background behind</div>

Position

<div class="relative">
  <!-- Parent: position: relative -->
  <div class="absolute top-0 right-0">
    <!-- positioned relative to parent -->
  </div>
</div>

<div class="fixed top-0 left-0 w-full">Sticky header</div>
<div class="sticky top-0">Sticky on scroll</div>

<!-- Z-index -->
<div class="z-10">z-index: 10</div>
<div class="z-50">z-index: 50</div>

Transitions and Animations

<!-- Transition all properties -->
<button class="bg-blue-600 hover:bg-blue-700 transition-colors duration-200 text-white px-4 py-2 rounded">
  Smooth color change
</button>

<!-- Transition specific properties -->
<div class="transition-transform duration-300 ease-in-out hover:scale-105">
  Scale on hover
</div>

<!-- Transition classes -->
<div class="transition-all duration-500 ease-in-out">all properties</div>
<div class="transition-opacity duration-200">opacity only</div>
<div class="transition-shadow">shadow only</div>

<!-- Duration -->
<!-- duration-75, duration-100, duration-150, duration-200,
     duration-300, duration-500, duration-700, duration-1000 -->

<!-- Easing -->
<div class="ease-linear">linear</div>
<div class="ease-in">ease-in</div>
<div class="ease-out">ease-out</div>
<div class="ease-in-out">ease-in-out</div>

<!-- Built-in animations -->
<div class="animate-spin">Spinning loader</div>
<div class="animate-ping">Ping effect (badges)</div>
<div class="animate-pulse">Pulsing (skeleton loading)</div>
<div class="animate-bounce">Bouncing</div>

Customization with tailwind.config.js

/** @type {import('tailwindcss').Config} */
export default {
  content: ["./src/**/*.{html,js,jsx,tsx}"],
  theme: {
    extend: {
      // Add custom colors
      colors: {
        brand: {
          50: '#eff6ff',
          500: '#3b82f6',
          900: '#1e3a5f',
        },
        accent: '#ff6b6b',
      },
      // Custom fonts
      fontFamily: {
        sans: ['Inter', 'system-ui', 'sans-serif'],
        heading: ['Poppins', 'sans-serif'],
      },
      // Custom spacing
      spacing: {
        '128': '32rem',
        '144': '36rem',
      },
      // Custom breakpoints
      screens: {
        'xs': '480px',
        '3xl': '1920px',
      },
      // Custom border radius
      borderRadius: {
        '4xl': '2rem',
      },
      // Custom animations
      animation: {
        'fade-in': 'fadeIn 0.5s ease-in-out',
        'slide-up': 'slideUp 0.3s ease-out',
      },
      keyframes: {
        fadeIn: {
          '0%': { opacity: '0' },
          '100%': { opacity: '1' },
        },
        slideUp: {
          '0%': { transform: 'translateY(20px)', opacity: '0' },
          '100%': { transform: 'translateY(0)', opacity: '1' },
        },
      },
    },
  },
  plugins: [],
}

Arbitrary Values

When you need a specific value not in the scale, use []:

<!-- Any CSS value -->
<div class="w-[327px]">exactly 327px</div>
<div class="mt-[42px]">margin-top: 42px</div>
<div class="bg-[#1a1a2e]">exact hex color</div>
<div class="text-[clamp(1rem,2.5vw,2rem)]">fluid typography</div>
<div class="grid-cols-[1fr_2fr_1fr]">custom grid columns</div>
<div class="top-[calc(100vh-80px)]">calc expression</div>

@apply Directive

Extract repeated utility patterns into CSS classes:

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

@layer components {
  .btn {
    @apply px-4 py-2 rounded font-medium transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2;
  }
  .btn-primary {
    @apply btn bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500;
  }
  .btn-secondary {
    @apply btn bg-gray-200 text-gray-900 hover:bg-gray-300 focus:ring-gray-400;
  }
  .input {
    @apply w-full border border-gray-300 rounded-md px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500;
  }
  .card {
    @apply bg-white rounded-xl shadow-md overflow-hidden;
  }
}

Use in HTML:

<button class="btn-primary">Save</button>
<button class="btn-secondary">Cancel</button>
<input class="input" placeholder="Enter email..." />
<div class="card p-6">...</div>

Plugins

Official Plugins

npm install @tailwindcss/typography @tailwindcss/forms @tailwindcss/aspect-ratio
// tailwind.config.js
plugins: [
  require('@tailwindcss/typography'),
  require('@tailwindcss/forms'),
  require('@tailwindcss/aspect-ratio'),
],
  • @tailwindcss/typography — beautiful prose styles for markdown content (.prose class)
  • @tailwindcss/forms — better default form styles
  • @tailwindcss/aspect-ratioaspect-w-16 aspect-h-9 for responsive video

Project 1: Landing Page Hero Section

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>SaaS Landing Page</title>
  <script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-white">

  <!-- Navigation -->
  <nav class="flex items-center justify-between px-6 py-4 max-w-7xl mx-auto">
    <div class="text-xl font-bold text-blue-600">Acme</div>
    <ul class="hidden md:flex items-center gap-8 text-gray-600 text-sm">
      <li><a href="#" class="hover:text-gray-900">Features</a></li>
      <li><a href="#" class="hover:text-gray-900">Pricing</a></li>
      <li><a href="#" class="hover:text-gray-900">Docs</a></li>
    </ul>
    <div class="flex items-center gap-3">
      <a href="#" class="hidden sm:block text-sm text-gray-600 hover:text-gray-900">Log in</a>
      <a href="#" class="bg-blue-600 hover:bg-blue-700 text-white text-sm px-4 py-2 rounded-lg transition-colors">
        Get started
      </a>
    </div>
  </nav>

  <!-- Hero -->
  <section class="text-center px-6 pt-16 pb-24 max-w-4xl mx-auto">
    <div class="inline-flex items-center gap-2 bg-blue-50 text-blue-700 text-sm px-3 py-1 rounded-full mb-6">
      <span class="w-2 h-2 bg-blue-500 rounded-full animate-pulse"></span>
      Now in public beta
    </div>
    <h1 class="text-5xl md:text-7xl font-bold text-gray-900 leading-tight mb-6">
      Build faster.<br>
      <span class="text-blue-600">Ship smarter.</span>
    </h1>
    <p class="text-xl text-gray-500 max-w-2xl mx-auto mb-10">
      The all-in-one platform for modern development teams. 
      Code, deploy, and scale — all in one place.
    </p>
    <div class="flex flex-col sm:flex-row items-center justify-center gap-4">
      <a href="#" class="w-full sm:w-auto bg-blue-600 hover:bg-blue-700 text-white font-medium px-8 py-3 rounded-xl transition-colors">
        Start for free
      </a>
      <a href="#" class="w-full sm:w-auto flex items-center justify-center gap-2 border border-gray-200 hover:border-gray-300 text-gray-700 font-medium px-8 py-3 rounded-xl transition-colors">
        Watch demo
      </a>
    </div>
  </section>

  <!-- Features Grid -->
  <section class="max-w-7xl mx-auto px-6 pb-24">
    <div class="grid grid-cols-1 md:grid-cols-3 gap-8">
      <div class="p-8 rounded-2xl border border-gray-100 hover:shadow-lg transition-shadow">
        <div class="w-12 h-12 bg-blue-100 rounded-xl flex items-center justify-center mb-4">
          <svg class="w-6 h-6 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"/>
          </svg>
        </div>
        <h3 class="text-lg font-semibold text-gray-900 mb-2">Lightning Fast</h3>
        <p class="text-gray-500 text-sm leading-relaxed">Deploy in seconds with our global edge network. Sub-100ms response times worldwide.</p>
      </div>
      <div class="p-8 rounded-2xl border border-gray-100 hover:shadow-lg transition-shadow">
        <div class="w-12 h-12 bg-green-100 rounded-xl flex items-center justify-center mb-4">
          <svg class="w-6 h-6 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"/>
          </svg>
        </div>
        <h3 class="text-lg font-semibold text-gray-900 mb-2">Secure by Default</h3>
        <p class="text-gray-500 text-sm leading-relaxed">SOC 2 compliant. End-to-end encryption. Automatic security updates.</p>
      </div>
      <div class="p-8 rounded-2xl border border-gray-100 hover:shadow-lg transition-shadow">
        <div class="w-12 h-12 bg-purple-100 rounded-xl flex items-center justify-center mb-4">
          <svg class="w-6 h-6 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 5a1 1 0 011-1h14a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM4 13a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6zM16 13a1 1 0 011-1h2a1 1 0 011 1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-6z"/>
          </svg>
        </div>
        <h3 class="text-lg font-semibold text-gray-900 mb-2">Scale Effortlessly</h3>
        <p class="text-gray-500 text-sm leading-relaxed">Auto-scales from zero to millions of users. Pay only for what you use.</p>
      </div>
    </div>
  </section>

</body>
</html>

Project 2: React Dashboard Card Component

// src/components/StatsCard.jsx
export function StatsCard({ title, value, change, icon, color = 'blue' }) {
  const colors = {
    blue: 'bg-blue-50 text-blue-600',
    green: 'bg-green-50 text-green-600',
    purple: 'bg-purple-50 text-purple-600',
    red: 'bg-red-50 text-red-600',
  }

  const isPositive = change >= 0

  return (
    <div className="bg-white rounded-xl border border-gray-100 shadow-sm p-6 hover:shadow-md transition-shadow">
      <div className="flex items-center justify-between mb-4">
        <p className="text-sm font-medium text-gray-500">{title}</p>
        <div className={`w-10 h-10 rounded-lg flex items-center justify-center ${colors[color]}`}>
          {icon}
        </div>
      </div>
      <p className="text-3xl font-bold text-gray-900 mb-2">{value}</p>
      <div className="flex items-center gap-1">
        <span className={`text-sm font-medium ${isPositive ? 'text-green-600' : 'text-red-600'}`}>
          {isPositive ? '↑' : '↓'} {Math.abs(change)}%
        </span>
        <span className="text-sm text-gray-500">vs last month</span>
      </div>
    </div>
  )
}

// src/App.jsx
import { StatsCard } from './components/StatsCard'

export default function Dashboard() {
  return (
    <div className="min-h-screen bg-gray-50">
      {/* Header */}
      <header className="bg-white border-b border-gray-200">
        <div className="max-w-7xl mx-auto px-6 py-4 flex items-center justify-between">
          <h1 className="text-xl font-bold text-gray-900">Dashboard</h1>
          <div className="flex items-center gap-3">
            <button className="text-gray-500 hover:text-gray-700 p-2 rounded-lg hover:bg-gray-100">
              🔔
            </button>
            <div className="w-8 h-8 bg-blue-600 rounded-full flex items-center justify-center text-white text-sm font-medium">
              JD
            </div>
          </div>
        </div>
      </header>

      <main className="max-w-7xl mx-auto px-6 py-8">
        {/* Welcome */}
        <div className="mb-8">
          <h2 className="text-2xl font-bold text-gray-900">Good morning, John! 👋</h2>
          <p className="text-gray-500 mt-1">Here's what's happening with your projects today.</p>
        </div>

        {/* Stats Grid */}
        <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
          <StatsCard title="Total Revenue" value="$45,231" change={20.1} color="blue" icon="💰" />
          <StatsCard title="Active Users" value="2,350" change={15.3} color="green" icon="👥" />
          <StatsCard title="New Orders" value="1,247" change={-3.2} color="purple" icon="📦" />
          <StatsCard title="Bounce Rate" value="24.3%" change={-8.1} color="red" icon="📉" />
        </div>

        {/* Recent Activity */}
        <div className="bg-white rounded-xl border border-gray-100 shadow-sm">
          <div className="p-6 border-b border-gray-100">
            <h3 className="font-semibold text-gray-900">Recent Activity</h3>
          </div>
          <ul className="divide-y divide-gray-50">
            {['New user signup: alice@example.com', 'Order #1234 completed', 'Payment received: $299', 'Server health check passed'].map((item, i) => (
              <li key={i} className="flex items-center gap-4 px-6 py-4 hover:bg-gray-50 transition-colors">
                <div className="w-2 h-2 rounded-full bg-blue-500 flex-shrink-0"></div>
                <p className="text-sm text-gray-700 flex-1">{item}</p>
                <span className="text-xs text-gray-400">{i + 1}m ago</span>
              </li>
            ))}
          </ul>
        </div>
      </main>
    </div>
  )
}

Project 3: Responsive Pricing Page

// src/components/Pricing.jsx
const plans = [
  {
    name: 'Starter',
    price: 0,
    description: 'Perfect for side projects',
    features: ['3 projects', '10GB storage', 'Community support', 'Basic analytics'],
    cta: 'Get started',
    highlighted: false,
  },
  {
    name: 'Pro',
    price: 29,
    description: 'For growing teams',
    features: ['Unlimited projects', '100GB storage', 'Priority support', 'Advanced analytics', 'Custom domains', 'Team collaboration'],
    cta: 'Start free trial',
    highlighted: true,
  },
  {
    name: 'Enterprise',
    price: 99,
    description: 'For large organizations',
    features: ['Unlimited everything', '1TB storage', '24/7 dedicated support', 'Custom analytics', 'SSO + SAML', 'SLA guarantee', 'Custom contracts'],
    cta: 'Contact sales',
    highlighted: false,
  },
]

export default function Pricing() {
  return (
    <section className="bg-gray-50 py-24 px-6">
      <div className="max-w-5xl mx-auto">
        {/* Header */}
        <div className="text-center mb-16">
          <h2 className="text-4xl font-bold text-gray-900 mb-4">Simple, transparent pricing</h2>
          <p className="text-xl text-gray-500">No hidden fees. Cancel anytime.</p>
        </div>

        {/* Plans */}
        <div className="grid grid-cols-1 md:grid-cols-3 gap-8">
          {plans.map((plan) => (
            <div
              key={plan.name}
              className={`relative rounded-2xl p-8 flex flex-col ${
                plan.highlighted
                  ? 'bg-blue-600 text-white shadow-2xl scale-105'
                  : 'bg-white border border-gray-200 shadow-sm'
              }`}
            >
              {plan.highlighted && (
                <div className="absolute -top-4 left-1/2 -translate-x-1/2">
                  <span className="bg-yellow-400 text-yellow-900 text-xs font-bold px-3 py-1 rounded-full uppercase tracking-wide">
                    Most Popular
                  </span>
                </div>
              )}

              <div className="mb-6">
                <h3 className={`text-lg font-semibold mb-1 ${plan.highlighted ? 'text-white' : 'text-gray-900'}`}>
                  {plan.name}
                </h3>
                <p className={`text-sm ${plan.highlighted ? 'text-blue-100' : 'text-gray-500'}`}>
                  {plan.description}
                </p>
              </div>

              <div className="mb-8">
                <span className={`text-5xl font-bold ${plan.highlighted ? 'text-white' : 'text-gray-900'}`}>
                  ${plan.price}
                </span>
                <span className={`text-sm ml-1 ${plan.highlighted ? 'text-blue-200' : 'text-gray-500'}`}>
                  /month
                </span>
              </div>

              <ul className="space-y-3 mb-8 flex-1">
                {plan.features.map((feature) => (
                  <li key={feature} className="flex items-center gap-3 text-sm">
                    <svg className={`w-4 h-4 flex-shrink-0 ${plan.highlighted ? 'text-blue-200' : 'text-green-500'}`} fill="none" stroke="currentColor" viewBox="0 0 24 24">
                      <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
                    </svg>
                    <span className={plan.highlighted ? 'text-blue-100' : 'text-gray-600'}>{feature}</span>
                  </li>
                ))}
              </ul>

              <button className={`w-full py-3 rounded-xl font-medium transition-colors ${
                plan.highlighted
                  ? 'bg-white text-blue-600 hover:bg-blue-50'
                  : 'bg-blue-600 text-white hover:bg-blue-700'
              }`}>
                {plan.cta}
              </button>
            </div>
          ))}
        </div>
      </div>
    </section>
  )
}

Common Tailwind Patterns

Card

<div class="bg-white rounded-xl shadow-md overflow-hidden max-w-sm">
  <img class="w-full h-48 object-cover" src="..." alt="..." />
  <div class="p-6">
    <span class="text-xs font-semibold text-blue-600 uppercase tracking-wide">Category</span>
    <h3 class="text-lg font-bold text-gray-900 mt-1 mb-2">Card Title</h3>
    <p class="text-gray-500 text-sm leading-relaxed">Card description goes here...</p>
    <button class="mt-4 text-blue-600 text-sm font-medium hover:text-blue-700">
      Read more →
    </button>
  </div>
</div>

Badge

<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
  Active
</span>
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-800">
  Inactive
</span>
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800">
  Pending
</span>

Avatar

<!-- Single avatar -->
<div class="w-10 h-10 rounded-full bg-blue-600 flex items-center justify-center text-white font-medium">
  JD
</div>

<!-- Avatar with image -->
<img class="w-10 h-10 rounded-full object-cover" src="..." alt="John Doe" />

<!-- Avatar group (overlapping) -->
<div class="flex -space-x-2">
  <img class="w-8 h-8 rounded-full ring-2 ring-white" src="..." alt="..." />
  <img class="w-8 h-8 rounded-full ring-2 ring-white" src="..." alt="..." />
  <img class="w-8 h-8 rounded-full ring-2 ring-white" src="..." alt="..." />
  <div class="w-8 h-8 rounded-full ring-2 ring-white bg-gray-200 flex items-center justify-center text-xs text-gray-600 font-medium">
    +5
  </div>
</div>

Alert / Toast

<!-- Success -->
<div class="flex items-center gap-3 bg-green-50 border border-green-200 text-green-800 rounded-lg px-4 py-3">
  <svg class="w-5 h-5 text-green-500 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
    <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/>
  </svg>
  <p class="text-sm font-medium">Operation completed successfully.</p>
</div>

<!-- Error -->
<div class="flex items-center gap-3 bg-red-50 border border-red-200 text-red-800 rounded-lg px-4 py-3">
  <svg class="w-5 h-5 text-red-500 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
    <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z" clip-rule="evenodd"/>
  </svg>
  <p class="text-sm font-medium">Something went wrong. Please try again.</p>
</div>

Loading Skeleton

<div class="animate-pulse space-y-4">
  <div class="h-4 bg-gray-200 rounded w-3/4"></div>
  <div class="h-4 bg-gray-200 rounded w-1/2"></div>
  <div class="h-4 bg-gray-200 rounded w-5/6"></div>
</div>

Modal

<!-- Backdrop + Modal -->
<div class="fixed inset-0 z-50 flex items-center justify-center p-4">
  <!-- Backdrop -->
  <div class="absolute inset-0 bg-black/50 backdrop-blur-sm"></div>
  
  <!-- Modal -->
  <div class="relative bg-white rounded-2xl shadow-xl w-full max-w-md p-6">
    <div class="flex items-center justify-between mb-4">
      <h3 class="text-lg font-semibold text-gray-900">Confirm Action</h3>
      <button class="text-gray-400 hover:text-gray-600 p-1 rounded">✕</button>
    </div>
    <p class="text-gray-500 text-sm mb-6">Are you sure you want to delete this item?</p>
    <div class="flex justify-end gap-3">
      <button class="px-4 py-2 text-sm text-gray-700 border border-gray-200 rounded-lg hover:bg-gray-50">Cancel</button>
      <button class="px-4 py-2 text-sm text-white bg-red-600 rounded-lg hover:bg-red-700">Delete</button>
    </div>
  </div>
</div>

Tailwind vs Related Terms

Term What it is
Tailwind CSS Utility-first CSS framework
Bootstrap Component-first CSS framework with pre-built UI
Tailwind UI Paid component library built with Tailwind (by Tailwind Labs)
shadcn/ui Free React component library using Tailwind + Radix UI
Headless UI Unstyled accessible components by Tailwind Labs
DaisyUI Free Tailwind component plugin
PostCSS CSS transformation tool Tailwind runs on
PurgeCSS Tree-shaking for CSS (built into Tailwind v3+)
CSS Modules Scoped CSS per component (different approach)
CSS-in-JS Styled-components, Emotion — different approach
Sass/SCSS CSS preprocessor — different approach
UnoCSS Atomic CSS engine, Tailwind alternative

Common Mistakes

Mistake Fix
Using CDN in production Use CLI or PostCSS build — CDN loads 3MB+ of CSS
Forgetting content paths in config List all files that use Tailwind — unused classes get purged
Using @apply excessively Prefer utility classes in HTML; @apply for truly shared patterns only
Not using group and peer Powerful for parent/sibling state changes
Adding arbitrary values for standard values Check the scale first — w-[16px] should be w-4
Missing dark: on all elements Test dark mode thoroughly — easy to miss nested elements
flex without specifying direction Default is flex-row, but be explicit with flex-col for vertical
Not configuring custom fonts Add fontFamily in config to avoid fallback fonts

Learning Path

Stage What to learn Time
1. Setup CDN, CLI, Vite setup 1 day
2. Core utilities Spacing, typography, colors, sizing 3 days
3. Layout Flex, Grid, responsive design 1 week
4. Interactive Hover, focus, transitions, dark mode 3 days
5. Customization tailwind.config.js, @apply, plugins 3 days
6. Real projects Build landing pages, dashboards 2 weeks
7. Ecosystem shadcn/ui, Headless UI, DaisyUI 1 week

Free Resources

Resource URL
Official Docs tailwindcss.com/docs
Tailwind Play play.tailwindcss.com (online playground)
shadcn/ui ui.shadcn.com
Headless UI headlessui.com
DaisyUI daisyui.com
Flowbite flowbite.com (free Tailwind components)
Tailwind Cheat Sheet nerdcave.com/tailwind-cheat-sheet

FAQ

Q: Should I use Tailwind or Bootstrap?
Tailwind if you want unique designs without fighting overrides. Bootstrap if you need a quick prototype and don't care about the "Bootstrap look". Tailwind has become far more popular for production apps in 2024–2025.

Q: Do I still write any CSS with Tailwind?
Rarely. Use tailwind.config.js for custom values and @layer components with @apply for truly repeated patterns. Most things don't need custom CSS.

Q: Isn't having hundreds of classes in HTML messy?
It can look cluttered. The tradeoff: you never need to look at a separate CSS file to understand styling. Extract complex patterns into React/Vue components. Use @apply for common utility groups.

Q: Does Tailwind work with TypeScript?
Yes. The config file has TypeScript support (tailwind.config.ts). Works perfectly with typed React/Vue/Angular projects.

Q: What's the difference between Tailwind CSS and Tailwind UI?
Tailwind CSS is free and open-source. Tailwind UI is a paid ($299 one-time) component library built with Tailwind by the same team. shadcn/ui is a free alternative.

Q: How do I add a custom font?

  1. Import in index.html or index.css (Google Fonts or local). 2. Add to tailwind.config.js under theme.extend.fontFamily. 3. Apply with font-sans or your custom key.

Quick Reference

<!-- Layout -->
flex flex-col flex-row items-center justify-between gap-4
grid grid-cols-3 col-span-2

<!-- Spacing -->
p-4 px-6 py-3 mt-8 mb-4 mx-auto space-y-4

<!-- Typography -->
text-xl font-bold text-gray-900 leading-tight tracking-wide uppercase

<!-- Colors -->
bg-white bg-blue-600 text-white text-gray-500 border-gray-200

<!-- Sizing -->
w-full h-screen max-w-7xl min-h-screen

<!-- Responsive -->
sm:flex md:hidden lg:grid-cols-3 xl:text-xl

<!-- State -->
hover:bg-blue-700 focus:ring-2 active:scale-95 disabled:opacity-50

<!-- Dark mode -->
dark:bg-gray-900 dark:text-white dark:border-gray-700

<!-- Animation -->
transition-colors duration-200 animate-pulse animate-spin

Keep reading

All Toolmingotools are free & run in your browser

No sign-up, no upload, no watermark. Your files never leave your device.

Browse all tools