Tailwind CSS Complete Guide | Utility-First, Responsive, Dark Mode, and Customization

Tailwind CSS Complete Guide | Utility-First, Responsive, Dark Mode, and Customization

What this post covers

This is a complete guide to building UIs quickly with Tailwind CSS—from installation through utility classes, responsive layouts, dark mode, customization, and plugins—with practical examples.

From the field: Migrating legacy CSS to Tailwind doubled our development speed and cut CSS bundle size by about 70%.

Introduction: “Writing CSS feels slow”

Real-world scenarios

Scenario 1: Naming classes is hard

BEM, SMACSS, and similar conventions add overhead. Tailwind relies on utility classes instead. Scenario 2: CSS files keep growing

Lots of unused CSS accumulates. Tailwind ships only what you use. Scenario 3: Responsive layouts are tedious

Writing media queries by hand is repetitive. Tailwind uses simple prefixes like md: and lg:.


1. What is Tailwind CSS?

Core traits

Tailwind CSS is a utility-first CSS framework. Main benefits:

  • Fast development: Style directly in your markup
  • Smaller bundles: Only used classes are included
  • Consistency: A built-in design system
  • Responsive design: Simple breakpoint prefixes
  • Customization: Fine-grained control

2. Installation

Vite + React

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

The example below uses JavaScript. Read through it and note what each part does.

// tailwind.config.js
export default {
  content: [
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

Here is a minimal CSS entry file. Run the app and confirm the layers load as expected.

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

3. Utility classes

Layout

The following HTML shows common layout utilities. Read each class in context.

<!-- Flexbox -->
<div class="flex items-center justify-between">
  <div>Left</div>
  <div>Right</div>
</div>
<!-- Grid -->
<div class="grid grid-cols-3 gap-4">
  <div>1</div>
  <div>2</div>
  <div>3</div>
</div>
<!-- Spacing -->
<div class="p-4 m-2">
  <div class="px-6 py-3">Content</div>
</div>

Typography

<h1 class="text-4xl font-bold text-gray-900">
  Heading
</h1>
<p class="text-base text-gray-600 leading-relaxed">
  Paragraph text
</p>
<a class="text-blue-600 hover:text-blue-800 underline">
  Link
</a>

Colors

<!-- Background -->
<div class="bg-blue-500 hover:bg-blue-600">
  Button
</div>
<!-- Text -->
<p class="text-red-500">Error message</p>
<!-- Border -->
<div class="border-2 border-gray-300">
  Box
</div>

4. Responsive design

Breakpoints

<!-- Mobile: column, desktop: row -->
<div class="flex flex-col md:flex-row">
  <div class="w-full md:w-1/2">Left</div>
  <div class="w-full md:w-1/2">Right</div>
</div>
<!-- Responsive text size -->
<h1 class="text-2xl md:text-4xl lg:text-6xl">
  Responsive Heading
</h1>
<!-- Responsive visibility -->
<div class="hidden md:block">
  Desktop only
</div>

Breakpoints:

  • sm: 640px
  • md: 768px
  • lg: 1024px
  • xl: 1280px
  • 2xl: 1536px

5. Dark mode

Configuration

// tailwind.config.js
export default {
  darkMode: 'class',  // or 'media'
  // ...
}

Usage

<div class="bg-white dark:bg-gray-900">
  <h1 class="text-gray-900 dark:text-white">
    Title
  </h1>
  <p class="text-gray-600 dark:text-gray-300">
    Content
  </p>
</div>

Toggle implementation

The example below uses TypeScript and React: import the hooks you need, keep dark mode in state, and toggle the dark class on the root element.

import { useEffect, useState } from 'react';
function ThemeToggle() {
  const [darkMode, setDarkMode] = useState(false);
  useEffect(() => {
    if (darkMode) {
      document.documentElement.classList.add('dark');
    } else {
      document.documentElement.classList.remove('dark');
    }
  }, [darkMode]);
  return (
    <button onClick={() => setDarkMode(!darkMode)}>
      {darkMode ? '🌞' : '🌙'}
    </button>
  );
}

6. Customization

Adding colors

// tailwind.config.js
export default {
  theme: {
    extend: {
      colors: {
        brand: {
          50: '#f0f9ff',
          100: '#e0f2fe',
          500: '#0ea5e9',
          900: '#0c4a6e',
        },
      },
    },
  },
}
<div class="bg-brand-500 text-white">
  Brand Color
</div>

Adding fonts

// tailwind.config.js
export default {
  theme: {
    extend: {
      fontFamily: {
        sans: ['Pretendard', 'sans-serif'],
        mono: ['Fira Code', 'monospace'],
      },
    },
  },
}

7. Extracting components

@apply

/* src/index.css */
@layer components {
  .btn {
    @apply px-4 py-2 rounded font-semibold transition;
  }
  .btn-primary {
    @apply bg-blue-500 text-white hover:bg-blue-600;
  }
  .btn-secondary {
    @apply bg-gray-200 text-gray-800 hover:bg-gray-300;
  }
}
<button class="btn btn-primary">
  Primary Button
</button>

8. Plugins

Official plugins

npm install -D @tailwindcss/forms @tailwindcss/typography @tailwindcss/aspect-ratio
// tailwind.config.js
export default {
  plugins: [
    require('@tailwindcss/forms'),
    require('@tailwindcss/typography'),
    require('@tailwindcss/aspect-ratio'),
  ],
}

Using Typography

<article class="prose lg:prose-xl dark:prose-invert">
  <h1>Title</h1>
  <p>This content will be beautifully styled automatically.</p>
</article>

9. Hands-on example: card component

interface CardProps {
  title: string;
  description: string;
  imageUrl: string;
  tags: string[];
}
export function Card({ title, description, imageUrl, tags }: CardProps) {
  return (
    <div class="max-w-sm rounded-lg overflow-hidden shadow-lg hover:shadow-xl transition-shadow duration-300 bg-white dark:bg-gray-800">
      <img 
        class="w-full h-48 object-cover" 
        src={imageUrl} 
        alt={title} 
      />
      
      <div class="p-6">
        <h2 class="text-2xl font-bold mb-2 text-gray-900 dark:text-white">
          {title}
        </h2>
        
        <p class="text-gray-600 dark:text-gray-300 mb-4">
          {description}
        </p>
        
        <div class="flex flex-wrap gap-2">
          {tags.map((tag) => (
            <span class="px-3 py-1 text-sm bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200 rounded-full">
              {tag}
            </span>
          ))}
        </div>
      </div>
    </div>
  );
}

Connecting this to interviews and your resume

Utility classes, design systems, and dark mode often come up in frontend interviews as productivity and UI consistency topics. See the Technical Interview Preparation Guide for how to talk about them, and the Developer Resume, Screening, and Interview Guide for quantifying UI improvements on your resume.


Summary and checklist

Key takeaways

  • Tailwind CSS: A utility-first CSS framework
  • Fast development: Style directly in your markup
  • Smaller bundles: Only used classes are included
  • Responsive design: Simple breakpoint prefixes
  • Dark mode: First-class support
  • Customization: Fine-grained control

Implementation checklist

  • Install Tailwind CSS
  • Learn core utility classes
  • Implement responsive layouts
  • Implement dark mode
  • Customize theme tokens
  • Add plugins

  • shadcn/ui Complete Guide
  • React 18 Deep Dive
  • Vite 5 Complete Guide

Keywords in this post

Tailwind CSS, CSS, Utility-First, Responsive, Dark Mode, Frontend, Design

Frequently asked questions (FAQ)

Q. Tailwind vs Bootstrap—which is better?

A. Tailwind is more flexible and easier to customize. Bootstrap ships prebuilt components. Prefer Tailwind for custom designs and Bootstrap for rapid prototypes.

Q. Doesn’t the HTML get messy?

A. It can feel that way at first, but once you are used to it, markup is often faster and clearer. Extract components and shared patterns to keep things tidy.

Q. What about performance?

A. Very strong. Unused classes are removed (for example with PurgeCSS or the built-in JIT pipeline), so production CSS bundles are often well under 10KB.

Q. Is it suitable for production?

A. Yes—many teams and products (for example GitHub, Netflix, and NASA) use it in production.