Jesse A. Green / notebook

Tailwind CSS User Guide

Generated May 2026 from tailwindlabs/tailwindcss at 5a835e1

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

Tailwind CSS is a utility-first CSS framework that lets you build custom designs directly in your HTML using a fixed vocabulary of composable class names like flex, px-4, text-lg, and bg-blue-500. Version 4 is a ground-up rewrite: configuration now lives in your CSS through directives like @theme, @source, and @plugin rather than a JavaScript config file. The class scanner runs in Rust via the Oxide engine, and the default theme ships with a curated OKLCH color palette.

This guide covers everything you need to install, configure, and use Tailwind CSS in your projects. For architecture details, plugin authoring internals, Oxide scanner implementation, and monorepo layout, see the Admin Guide.


1. Quick Start

Get a working Tailwind CSS project in under two minutes.

1.1 The Fastest Path: Vite

npm create vite@latest my-project -- --template vanilla
cd my-project
npm install tailwindcss @tailwindcss/vite

Add the Vite plugin to vite.config.js:

import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'

export default defineConfig({
  plugins: [
    tailwindcss(),
  ],
})

Replace the contents of src/style.css:

@import 'tailwindcss';

Add utility classes to your HTML:

<h1 class="text-3xl font-bold text-blue-600 underline">
  Hello, Tailwind!
</h1>

Start the dev server:

npm run dev

That single @import 'tailwindcss' line pulls in Preflight (a modern CSS reset), the full default theme, and all utility class generation. Every class you use in your markup is detected automatically and compiled into your CSS output.

1.2 The Fastest Path: CLI

If you have no build tool at all:

npx @tailwindcss/cli -i input.css -o output.css --watch

Where input.css contains @import 'tailwindcss';. The CLI watches your project files and regenerates output.css whenever you save.

1.3 The Fastest Path: CDN (Browser Build)

For prototyping with zero tooling:

<!DOCTYPE html>
<html>
<head>
  <script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
</head>
<body>
  <h1 class="text-3xl font-bold text-purple-700">
    Instant Tailwind
  </h1>
</body>
</html>

Warning

The browser build is for prototyping only. It compiles in the browser at runtime, does not support @import of external files, and does not support JS plugins or config files. Never use it in production.


2. Installation

Tailwind CSS v4 requires Node.js 20 or later. There are six integration paths depending on your build setup.

2.1 Requirements

Requirement Version
Node.js >= 20
npm / pnpm / yarn / bun Any current release
License MIT

Note

Tailwind v4 ships native binaries for the Oxide scanner. Supported platforms include Linux x64 (glibc and musl), Linux ARM64, macOS x64, macOS ARM64, and Windows x64. If your platform is not supported, you will see an error at install time (see Troubleshooting).

2.2 Using the Vite Plugin

The Vite plugin (@tailwindcss/vite) is the recommended integration for Vite-based projects. It provides the fastest development experience with hot module replacement (HMR).

npm install tailwindcss @tailwindcss/vite
// vite.config.js
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'

export default defineConfig({
  plugins: [
    tailwindcss(),
  ],
})

Create your CSS entry point:

/* src/app.css */
@import 'tailwindcss';

Import the CSS in your application entry:

// src/main.js
import './app.css'

Vite Plugin with React

npm install tailwindcss @tailwindcss/vite
// vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import tailwindcss from '@tailwindcss/vite'

export default defineConfig({
  plugins: [
    react(),
    tailwindcss(),
  ],
})

Vite Plugin with Vue

npm install tailwindcss @tailwindcss/vite
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import tailwindcss from '@tailwindcss/vite'

export default defineConfig({
  plugins: [
    vue(),
    tailwindcss(),
  ],
})

Vite Plugin with Svelte

npm install tailwindcss @tailwindcss/vite
// vite.config.js
import { defineConfig } from 'vite'
import { svelte } from '@sveltejs/vite-plugin-svelte'
import tailwindcss from '@tailwindcss/vite'

export default defineConfig({
  plugins: [
    svelte(),
    tailwindcss(),
  ],
})

2.3 Using PostCSS

The PostCSS plugin (@tailwindcss/postcss) integrates Tailwind into any PostCSS-compatible build tool.

npm install tailwindcss @tailwindcss/postcss

Add to your PostCSS configuration:

// postcss.config.js
export default {
  plugins: {
    '@tailwindcss/postcss': {},
  },
}

Create your CSS entry point:

/* src/app.css */
@import 'tailwindcss';

Tip

If you are using a framework that already has PostCSS configured (like Next.js, Nuxt, or Angular), you only need to add @tailwindcss/postcss to the existing PostCSS config. You do not need to install PostCSS separately.

PostCSS with Next.js

npm install tailwindcss @tailwindcss/postcss
// postcss.config.mjs
const config = {
  plugins: {
    '@tailwindcss/postcss': {},
  },
}
export default config

In your global CSS file (e.g., app/globals.css):

@import 'tailwindcss';

PostCSS with Nuxt

npm install tailwindcss @tailwindcss/postcss
// postcss.config.js
export default {
  plugins: {
    '@tailwindcss/postcss': {},
  },
}

In your Nuxt CSS entry (configured in nuxt.config.ts):

@import 'tailwindcss';

PostCSS with Angular

npm install tailwindcss @tailwindcss/postcss

Angular's CLI reads .postcssrc.json automatically:

{
  "plugins": {
    "@tailwindcss/postcss": {}
  }
}

In your src/styles.css:

@import 'tailwindcss';

2.4 Using the CLI

The CLI (@tailwindcss/cli) is a standalone build tool that requires no framework integration.

npm install tailwindcss @tailwindcss/cli

CLI Commands

Command Description
build (default) Compile CSS input to output
canonicalize Normalize and reformat Tailwind CSS input

CLI Flags

Flag Short Description
--input -i Path to the input CSS file
--output -o Path to write the compiled CSS
--watch -w Watch for changes and rebuild automatically
--minify Minify the output CSS
--help -h Show help information
- (stdin) Read input from stdin
- (stdout) Write output to stdout

Basic Build

npx @tailwindcss/cli -i src/app.css -o dist/output.css

Watch Mode

npx @tailwindcss/cli -i src/app.css -o dist/output.css --watch

Minified Production Build

npx @tailwindcss/cli -i src/app.css -o dist/output.css --minify

Pipe via stdin/stdout

cat src/app.css | npx @tailwindcss/cli -i - -o -

This is useful for integrating with other tools in a Unix pipeline.

Canonicalize

The canonicalize command normalizes your Tailwind CSS file, reordering directives and formatting consistently:

npx @tailwindcss/cli canonicalize -i src/app.css -o src/app.css

Using with npm Scripts

{
  "scripts": {
    "dev": "tailwindcss -i src/app.css -o dist/output.css --watch",
    "build": "tailwindcss -i src/app.css -o dist/output.css --minify"
  }
}

2.5 Using Webpack

The Webpack loader (@tailwindcss/webpack) integrates Tailwind into Webpack-based projects.

npm install tailwindcss @tailwindcss/webpack
// webpack.config.js
const tailwindcss = require('@tailwindcss/webpack')

module.exports = {
  // ...
  plugins: [
    tailwindcss(),
  ],
}

Create your CSS entry point:

/* src/app.css */
@import 'tailwindcss';

2.6 Using the Standalone Binary

The standalone CLI (@tailwindcss/standalone) is a self-contained binary that does not require Node.js. It bundles everything needed to compile Tailwind CSS, including several popular first-party plugins.

Download

Download the binary for your platform from the GitHub releases page, or install it:

npm install @tailwindcss/standalone

Built-in Plugins

The standalone binary includes these plugins with no additional installation:

  • @tailwindcss/forms
  • @tailwindcss/typography
  • @tailwindcss/aspect-ratio

Usage

./tailwindcss -i src/app.css -o dist/output.css --watch

The standalone binary accepts the same flags as the standard CLI (--input, --output, --watch, --minify).

Tip

The standalone binary is ideal for environments where Node.js is not available or not desired, such as CI pipelines, Docker containers with minimal images, or non-Node projects (PHP, Ruby, Python, Go, etc.).

2.7 Using the Browser Build

The browser build (@tailwindcss/browser) compiles Tailwind CSS entirely in the browser at runtime.

<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>

Or with a specific version:

<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4.2.2"></script>

Inline Tailwind CSS

You can write Tailwind directives in a <style> tag with type="text/tailwindcss":

<style type="text/tailwindcss">
  @theme {
    --color-primary: #3b82f6;
  }
</style>

<h1 class="text-primary font-bold text-4xl">Hello</h1>

Browser Build Limitations

The browser build has specific constraints:

  • @import for external files is not supported
  • JS plugins (@plugin) are not supported
  • JS config files (@config) are not supported
  • Compilation happens at runtime (performance impact on page load)
  • Not suitable for production use

2.8 Granular CSS Imports

Instead of importing all of Tailwind with @import 'tailwindcss', you can import individual layers:

/* Preflight only (CSS reset) */
@import 'tailwindcss/preflight';

/* Theme variables only */
@import 'tailwindcss/theme';

/* Utility classes only */
@import 'tailwindcss/utilities';

This gives you control over which parts of Tailwind are included. For example, if you already have your own CSS reset:

/* Skip Preflight, use theme + utilities only */
@import 'tailwindcss/theme';
@import 'tailwindcss/utilities';

Or if you want to insert custom base styles between Preflight and utilities:

@import 'tailwindcss/preflight';
@import 'tailwindcss/theme';

/* Your custom base styles here */
body {
  font-family: 'Inter', sans-serif;
}

@import 'tailwindcss/utilities';

3. Configuration

Tailwind CSS v4 uses a CSS-first configuration model. Instead of a tailwind.config.js file, you configure Tailwind directly in your CSS using special directives.

3.1 Configuration Directives Overview

Directive Purpose
@theme Define and override design tokens (colors, spacing, fonts, etc.)
@source Control which files are scanned for class candidates
@plugin Load JavaScript plugins
@config Load a legacy tailwind.config.js file
@variant Define custom variants
@utility Define custom utility classes
@apply Use utility classes inside custom CSS
@reference Reference another CSS file without including its output

3.2 The @theme Directive

The @theme directive defines design tokens as CSS custom properties. These tokens generate the utility classes Tailwind provides.

Basic Theme Customization

@import 'tailwindcss';

@theme {
  --color-primary: #3b82f6;
  --color-secondary: #8b5cf6;
  --color-accent: #f59e0b;
  --font-family-display: 'Cal Sans', sans-serif;
  --font-family-body: 'Inter', sans-serif;
}

This makes classes like text-primary, bg-secondary, text-accent, font-display, and font-body available throughout your project.

Namespace Prefixes

Theme values are organized by namespace prefix. Each prefix maps to a category of utilities:

Prefix Generates Example Class
--color-* Color utilities text-brand, bg-brand, border-brand
--spacing-* Spacing utilities p-gutter, m-gutter, gap-gutter
--font-family-* Font family utilities font-display
--font-size-* Font size utilities text-heading
--font-weight-* Font weight utilities font-medium
--breakpoint-* Responsive breakpoints md:, lg:, xl:
--width-* Width utilities w-sidebar
--height-* Height utilities h-header
--radius-* Border radius utilities rounded-card
--shadow-* Box shadow utilities shadow-card
--tracking-* Letter spacing utilities tracking-wide
--leading-* Line height utilities leading-relaxed
--ease-* Transition timing ease-bounce
--animate-* Animation utilities animate-slide-in
--inset-shadow-* Inset shadow utilities inset-shadow-lg

Defining Colors

@theme {
  --color-brand-50: #eff6ff;
  --color-brand-100: #dbeafe;
  --color-brand-200: #bfdbfe;
  --color-brand-300: #93c5fd;
  --color-brand-400: #60a5fa;
  --color-brand-500: #3b82f6;
  --color-brand-600: #2563eb;
  --color-brand-700: #1d4ed8;
  --color-brand-800: #1e40af;
  --color-brand-900: #1e3a8a;
  --color-brand-950: #172554;
}

This generates text-brand-500, bg-brand-200, border-brand-700, ring-brand-400, and all other color-related utilities for every shade.

Defining Spacing

@theme {
  --spacing-gutter: 1.5rem;
  --spacing-section: 4rem;
  --spacing-sidebar: 16rem;
}

Generates p-gutter, m-section, gap-gutter, w-sidebar, and so on.

Defining Breakpoints

@theme {
  --breakpoint-xs: 30rem;
  --breakpoint-sm: 40rem;
  --breakpoint-md: 48rem;
  --breakpoint-lg: 64rem;
  --breakpoint-xl: 80rem;
  --breakpoint-2xl: 96rem;
}

Generates responsive variants like xs:, sm:, md:, lg:, xl:, 2xl:.

Defining Fonts

@theme {
  --font-family-sans: 'Inter', ui-sans-serif, system-ui, sans-serif;
  --font-family-serif: 'Merriweather', ui-serif, Georgia, serif;
  --font-family-mono: 'JetBrains Mono', ui-monospace, monospace;

  --font-size-xs: 0.75rem;
  --font-size-sm: 0.875rem;
  --font-size-base: 1rem;
  --font-size-lg: 1.125rem;
  --font-size-xl: 1.25rem;
  --font-size-2xl: 1.5rem;
  --font-size-3xl: 1.875rem;
  --font-size-4xl: 2.25rem;

  --font-weight-thin: 100;
  --font-weight-light: 300;
  --font-weight-normal: 400;
  --font-weight-medium: 500;
  --font-weight-semibold: 600;
  --font-weight-bold: 700;
  --font-weight-black: 900;
}

Defining Shadows

@theme {
  --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
  --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
  --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
  --shadow-card: 0 2px 8px rgb(0 0 0 / 0.08);
  --shadow-elevated: 0 8px 24px rgb(0 0 0 / 0.12);
}

Defining Animations

@theme {
  --animate-fade-in: fade-in 0.3s ease-out;
  --animate-slide-up: slide-up 0.4s ease-out;
  --animate-bounce-in: bounce-in 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}

@keyframes fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes slide-up {
  from { transform: translateY(1rem); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}

@keyframes bounce-in {
  from { transform: scale(0.9); opacity: 0; }
  to { transform: scale(1); opacity: 1; }
}

Generates animate-fade-in, animate-slide-up, animate-bounce-in.

Defining Transition Timing

@theme {
  --ease-bounce: cubic-bezier(0.68, -0.55, 0.265, 1.55);
  --ease-smooth: cubic-bezier(0.4, 0, 0.2, 1);
}

Generates ease-bounce, ease-smooth.

Defining Border Radius

@theme {
  --radius-sm: 0.25rem;
  --radius-md: 0.375rem;
  --radius-lg: 0.5rem;
  --radius-xl: 0.75rem;
  --radius-2xl: 1rem;
  --radius-full: 9999px;
  --radius-card: 0.75rem;
  --radius-button: 0.5rem;
}

Resetting the Default Theme

To start from scratch with no default theme values, reset all defaults:

@theme {
  --*: initial;
}

This removes every built-in design token. You must then define all your own tokens from zero. Classes like text-blue-500 will no longer work unless you re-define those color tokens.

You can also reset specific namespaces:

@theme {
  --color-*: initial;

  /* Now define only the colors you want */
  --color-primary: #3b82f6;
  --color-gray-100: #f3f4f6;
  --color-gray-900: #111827;
}

Important

Resetting with --*: initial removes ALL default Tailwind theme values. This means default colors like blue-500, default spacing, default breakpoints, and all other built-in tokens disappear. Only do this if you intend to define a complete custom design system.

Multiple @theme Blocks

You can use multiple @theme blocks. They merge together:

@import 'tailwindcss';

@theme {
  --color-primary: #3b82f6;
}

@theme {
  --color-secondary: #8b5cf6;
}

Both primary and secondary colors will be available.

3.3 The @source Directive

The @source directive tells Tailwind which files to scan for utility class candidates. By default, Tailwind scans all files in your project directory (respecting .gitignore), but you can customize this.

Adding Source Paths

@import 'tailwindcss';

@source '../components/**/*.jsx';
@source '../layouts/**/*.html';
@source '../node_modules/my-ui-lib/src/**/*.js';

Glob Pattern Syntax

Pattern Matches
* Any file in a single directory
** Any file recursively
*.jsx Any .jsx file in a single directory
**/*.{html,jsx,tsx} Any .html, .jsx, or .tsx file recursively
../packages/ui/**/*.tsx Files in a sibling package

Scanning Node Modules

By default, node_modules is excluded. To scan a specific package:

@source '../node_modules/@my-org/ui-components/**/*.js';

Source Directory Base

The source(...) function references a directory that all @source glob patterns are relative to:

@import 'tailwindcss' source('../src');

This changes the base directory for automatic scanning from your CSS file's location to ../src.

Note

The @source directive respects your .gitignore file. If a file or directory is listed in .gitignore, Tailwind will not scan it for class candidates even if it matches a @source glob pattern. This can cause confusion when @source appears to silently ignore paths (see Troubleshooting for issue #19844).

Source with none

Disable automatic source detection entirely:

@import 'tailwindcss' source(none);

/* Only scan explicitly listed sources */
@source '../app/**/*.tsx';
@source '../components/**/*.tsx';

Scanning Non-Standard File Types

The Oxide engine automatically detects and extracts class candidates from many file types beyond HTML and JavaScript:

Language/Format File Extensions
Clojure .clj, .cljs, .cljc
Elixir .ex, .exs, .heex, .leex
Haml .haml
JSON .json
Markdown .md, .mdx
Pug .pug, .jade
Razor .cshtml, .razor
Ruby .rb, .erb
Rust .rs
Slim .slim
Svelte .svelte
Vue .vue

3.4 The @plugin Directive

Load JavaScript plugins directly from your CSS:

@import 'tailwindcss';

@plugin '@tailwindcss/typography';
@plugin '@tailwindcss/forms';
@plugin './my-custom-plugin.js';

Plugins must be installed in your node_modules or referenced as a relative path. Each plugin can register new utilities, variants, base styles, and components.

Plugin Purpose
@tailwindcss/typography Beautiful typographic defaults for prose content
@tailwindcss/forms Improved form element styling
@tailwindcss/aspect-ratio Aspect ratio utilities (v3 compat)

3.5 The @config Directive

For backward compatibility, you can load a legacy tailwind.config.js file:

@import 'tailwindcss';

@config '../tailwind.config.js';

This is a migration path from v3. The CSS-first configuration (@theme, @plugin, etc.) is the recommended approach for new projects.

Tip

Use the @tailwindcss/upgrade tool to automatically migrate your v3 tailwind.config.js to v4 CSS-first configuration. See the "Upgrading from Tailwind v3" section for details.

3.6 The @reference Directive

The @reference directive lets you reference another CSS file for type-checking and IntelliSense without actually including its output in your build:

@reference '../app.css';

.my-component {
  @apply text-primary bg-secondary;
}

This is useful when you have component-level CSS files that need access to your theme tokens and custom utilities defined in a different file, without duplicating that file's output.

3.7 Theme Functions

Tailwind v4 provides CSS functions for referencing theme values dynamically.

--theme(...)

Reference any theme token value:

.custom-element {
  color: var(--color-primary);
  background-color: --theme(--color-brand-100);
  border: 1px solid --theme(--color-brand-300);
}

Caution

The --theme(...) function can only be used with CSS variables defined in your @theme block. Attempting to use it with non-theme variables produces: The --theme(...) function can only be used with CSS variables from your theme.

--spacing(...)

Reference the spacing scale:

.custom-element {
  padding: --spacing(4);
  margin-bottom: --spacing(8);
  gap: --spacing(2);
}

The argument maps to your spacing scale (e.g., --spacing(4) = 1rem in the default theme). Passing no argument produces an error: The --spacing(...) function requires an argument, but received none.

3.8 Compatibility Exports

For backward compatibility with v3-era tooling and plugins, Tailwind CSS v4 provides these JavaScript exports:

Export Import Path
Default colors tailwindcss/colors
Default theme values tailwindcss/defaultTheme
Plugin helper tailwindcss/plugin
Color utility tailwindcss/lib/util/flattenColorPalette
// Accessing default colors in a plugin or config
import colors from 'tailwindcss/colors'

console.log(colors.blue[500]) // '#3b82f6'
// Using the plugin helper
import plugin from 'tailwindcss/plugin'

export default plugin(function({ addUtilities }) {
  addUtilities({
    '.content-auto': {
      'content-visibility': 'auto',
    },
  })
})

4. Core Usage

4.1 How Utility Classes Work

Every Tailwind utility class maps to one or a small number of CSS property declarations. You compose them in your HTML class attribute to build designs:

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

This renders a card with flexbox layout, centered items, a gap between children, padding, white background, rounded corners, and a shadow. No custom CSS written.

4.2 Layout Utilities

Flexbox

<!-- Row layout (default) -->
<div class="flex gap-4">
  <div>Item 1</div>
  <div>Item 2</div>
  <div>Item 3</div>
</div>

<!-- Column layout -->
<div class="flex flex-col gap-2">
  <div>Row 1</div>
  <div>Row 2</div>
  <div>Row 3</div>
</div>

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

<!-- Space between -->
<nav class="flex items-center justify-between px-6 py-4">
  <div class="text-xl font-bold">Logo</div>
  <div class="flex gap-6">
    <a href="#">Home</a>
    <a href="#">About</a>
    <a href="#">Contact</a>
  </div>
</nav>

<!-- Wrap items -->
<div class="flex flex-wrap gap-2">
  <span class="px-3 py-1 bg-blue-100 text-blue-800 rounded-full">Tag 1</span>
  <span class="px-3 py-1 bg-blue-100 text-blue-800 rounded-full">Tag 2</span>
  <span class="px-3 py-1 bg-blue-100 text-blue-800 rounded-full">Tag 3</span>
</div>

<!-- Flex grow and shrink -->
<div class="flex">
  <div class="w-64 shrink-0">Sidebar</div>
  <div class="grow">Main content</div>
</div>

Grid

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

<!-- Responsive grid -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
  <div>Card 1</div>
  <div>Card 2</div>
  <div>Card 3</div>
</div>

<!-- Spanning columns -->
<div class="grid grid-cols-4 gap-4">
  <div class="col-span-2">Wide item</div>
  <div>Normal</div>
  <div>Normal</div>
</div>

<!-- Auto-fit columns -->
<div class="grid grid-cols-[repeat(auto-fit,minmax(250px,1fr))] gap-4">
  <div>Auto-sized card</div>
  <div>Auto-sized card</div>
  <div>Auto-sized card</div>
</div>

Container

<div class="container mx-auto px-4">
  <!-- Constrained-width content centered on the page -->
</div>

Position

<!-- Sticky header -->
<header class="sticky top-0 z-50 bg-white shadow-sm">
  <nav class="container mx-auto px-4 py-3">...</nav>
</header>

<!-- Absolute positioning -->
<div class="relative">
  <img src="hero.jpg" class="w-full h-96 object-cover">
  <div class="absolute inset-0 bg-black/50 flex items-center justify-center">
    <h1 class="text-4xl font-bold text-white">Hero Title</h1>
  </div>
</div>

<!-- Fixed footer -->
<footer class="fixed bottom-0 inset-x-0 bg-gray-900 text-white p-4">
  Fixed footer content
</footer>

4.3 Spacing Utilities

Tailwind's spacing scale uses a consistent 0.25rem (4px) increment by default.

Class CSS Pixels (at 16px base)
p-0 padding: 0 0px
p-px padding: 1px 1px
p-0.5 padding: 0.125rem 2px
p-1 padding: 0.25rem 4px
p-2 padding: 0.5rem 8px
p-3 padding: 0.75rem 12px
p-4 padding: 1rem 16px
p-6 padding: 1.5rem 24px
p-8 padding: 2rem 32px
p-12 padding: 3rem 48px
p-16 padding: 4rem 64px
p-24 padding: 6rem 96px
p-32 padding: 8rem 128px
p-48 padding: 12rem 192px
p-64 padding: 16rem 256px

The same scale applies to margin (m-*), gap (gap-*), width (w-*), height (h-*), top/right/bottom/left inset utilities, and more.

Directional Spacing

<!-- All sides -->
<div class="p-4 m-4">...</div>

<!-- Horizontal / Vertical -->
<div class="px-6 py-4 mx-auto my-8">...</div>

<!-- Individual sides -->
<div class="pt-2 pr-4 pb-6 pl-8 mt-4 mr-2 mb-6 ml-0">...</div>

<!-- Logical properties (start/end for RTL support) -->
<div class="ps-4 pe-6 ms-2 me-4">...</div>

Negative Margins

Prefix with a dash:

<div class="-mt-4 -mx-2">Overlapping content</div>

Space Between Children

<div class="space-y-4">
  <p>First paragraph</p>
  <p>Second paragraph (4 spacing units below first)</p>
  <p>Third paragraph (4 spacing units below second)</p>
</div>

<div class="flex space-x-3">
  <button>One</button>
  <button>Two</button>
  <button>Three</button>
</div>

4.4 Typography Utilities

Font Size

<p class="text-xs">Extra small (0.75rem / 12px)</p>
<p class="text-sm">Small (0.875rem / 14px)</p>
<p class="text-base">Base (1rem / 16px)</p>
<p class="text-lg">Large (1.125rem / 18px)</p>
<p class="text-xl">Extra large (1.25rem / 20px)</p>
<p class="text-2xl">2XL (1.5rem / 24px)</p>
<p class="text-3xl">3XL (1.875rem / 30px)</p>
<p class="text-4xl">4XL (2.25rem / 36px)</p>
<p class="text-5xl">5XL (3rem / 48px)</p>
<p class="text-6xl">6XL (3.75rem / 60px)</p>
<p class="text-7xl">7XL (4.5rem / 72px)</p>
<p class="text-8xl">8XL (6rem / 96px)</p>
<p class="text-9xl">9XL (8rem / 128px)</p>

Font Weight

<p class="font-thin">Thin (100)</p>
<p class="font-light">Light (300)</p>
<p class="font-normal">Normal (400)</p>
<p class="font-medium">Medium (500)</p>
<p class="font-semibold">Semibold (600)</p>
<p class="font-bold">Bold (700)</p>
<p class="font-extrabold">Extrabold (800)</p>
<p class="font-black">Black (900)</p>

Font Family

<p class="font-sans">Sans-serif text</p>
<p class="font-serif">Serif text</p>
<p class="font-mono">Monospace text</p>

Text Color

<p class="text-gray-900">Dark text</p>
<p class="text-gray-500">Muted text</p>
<p class="text-blue-600">Accent text</p>
<p class="text-red-500">Error text</p>
<p class="text-white">White text</p>

Text Alignment

<p class="text-left">Left-aligned</p>
<p class="text-center">Centered</p>
<p class="text-right">Right-aligned</p>
<p class="text-justify">Justified text</p>

Text Decoration

<a class="underline">Underlined link</a>
<a class="no-underline">No underline</a>
<p class="line-through">Strikethrough</p>
<p class="underline decoration-blue-500 decoration-2">Custom underline</p>
<p class="underline decoration-wavy decoration-red-500">Wavy underline</p>
<p class="underline underline-offset-4">Offset underline</p>

Text Transform

<p class="uppercase">UPPERCASE</p>
<p class="lowercase">lowercase</p>
<p class="capitalize">Capitalize Each Word</p>
<p class="normal-case">Normal Case</p>

Line Height (Leading)

<p class="leading-none">Tight (1)</p>
<p class="leading-tight">Tight (1.25)</p>
<p class="leading-snug">Snug (1.375)</p>
<p class="leading-normal">Normal (1.5)</p>
<p class="leading-relaxed">Relaxed (1.625)</p>
<p class="leading-loose">Loose (2)</p>

Letter Spacing (Tracking)

<p class="tracking-tighter">Tighter</p>
<p class="tracking-tight">Tight</p>
<p class="tracking-normal">Normal</p>
<p class="tracking-wide">Wide</p>
<p class="tracking-wider">Wider</p>
<p class="tracking-widest">Widest</p>

Text Overflow

<!-- Truncate with ellipsis -->
<p class="truncate w-64">
  This very long text will be truncated with an ellipsis...
</p>

<!-- Line clamp (multi-line truncation) -->
<p class="line-clamp-3">
  This text will show at most 3 lines and then be
  truncated with an ellipsis at the end of the third line.
</p>

Whitespace

<p class="whitespace-nowrap">Text that won't wrap</p>
<p class="whitespace-pre">Preserves    whitespace</p>
<p class="whitespace-pre-line">Preserves line breaks only</p>
<p class="whitespace-pre-wrap">Preserves whitespace and wraps</p>
<p class="break-words">Break words to prevent overflow</p>
<p class="break-all">Break at any character</p>

4.5 Color Utilities

Colors apply to many properties. Each color in your theme generates utilities across all color-aware properties:

<!-- Text color -->
<p class="text-blue-600">Blue text</p>

<!-- Background color -->
<div class="bg-gray-100">Gray background</div>

<!-- Border color -->
<div class="border border-gray-300">Gray border</div>

<!-- Ring color (focus rings) -->
<button class="ring-2 ring-blue-500">Focused button</button>

<!-- Divide color -->
<div class="divide-y divide-gray-200">
  <div>Item 1</div>
  <div>Item 2</div>
</div>

<!-- Outline color -->
<button class="outline-2 outline-blue-500">Outlined button</button>

<!-- Placeholder color -->
<input class="placeholder-gray-400" placeholder="Enter text...">

<!-- Accent color (for form elements) -->
<input type="checkbox" class="accent-blue-600">

<!-- Caret color -->
<input class="caret-blue-600" type="text">

<!-- Shadow color -->
<div class="shadow-lg shadow-blue-500/20">Blue-tinted shadow</div>

Opacity Modifier

Apply opacity to any color utility with the / syntax:

<div class="bg-blue-500/50">50% opacity blue background</div>
<div class="bg-black/75">75% opacity black overlay</div>
<p class="text-red-600/80">80% opacity red text</p>
<div class="border border-gray-900/10">10% opacity border</div>

The number after / is the opacity percentage (0-100).

Current Color and Inherit

<p class="text-blue-600">
  <a class="text-current underline">Inherits parent blue</a>
</p>
<p class="text-inherit">Inherits from CSS cascade</p>

4.6 Background Utilities

<!-- Solid colors -->
<div class="bg-white">White</div>
<div class="bg-gray-50">Light gray</div>
<div class="bg-transparent">Transparent</div>

<!-- Gradients -->
<div class="bg-gradient-to-r from-blue-500 to-purple-600">
  Left to right gradient
</div>
<div class="bg-gradient-to-br from-green-400 via-blue-500 to-purple-600">
  Diagonal gradient with midpoint
</div>

<!-- Background size -->
<div class="bg-cover bg-center" style="background-image: url('hero.jpg')">
  Cover image
</div>
<div class="bg-contain bg-no-repeat bg-center">
  Contained image
</div>

<!-- Background position -->
<div class="bg-top">Top</div>
<div class="bg-center">Center</div>
<div class="bg-bottom">Bottom</div>
<div class="bg-left-top">Top left</div>

4.7 Border Utilities

<!-- Border width -->
<div class="border">1px border all sides</div>
<div class="border-2">2px border</div>
<div class="border-4">4px border</div>
<div class="border-t-2">2px top border only</div>
<div class="border-b">1px bottom border</div>
<div class="border-x-2">2px horizontal borders</div>
<div class="border-y">1px vertical borders</div>

<!-- Border color -->
<div class="border border-gray-300">Gray border</div>
<div class="border-2 border-blue-500">Blue border</div>

<!-- Border style -->
<div class="border-solid">Solid</div>
<div class="border-dashed">Dashed</div>
<div class="border-dotted">Dotted</div>
<div class="border-none">No border</div>

<!-- Border radius -->
<div class="rounded">Default radius</div>
<div class="rounded-md">Medium radius</div>
<div class="rounded-lg">Large radius</div>
<div class="rounded-xl">Extra-large radius</div>
<div class="rounded-2xl">2XL radius</div>
<div class="rounded-full">Full (pill/circle)</div>
<div class="rounded-none">No radius</div>
<div class="rounded-t-lg">Top corners only</div>
<div class="rounded-b-lg">Bottom corners only</div>
<div class="rounded-l-lg">Left corners only</div>
<div class="rounded-r-lg">Right corners only</div>

<!-- Ring (outline ring) -->
<button class="ring-2 ring-blue-500 ring-offset-2">Focus ring</button>

<!-- Divide (borders between children) -->
<div class="divide-y divide-gray-200">
  <div class="py-3">Item 1</div>
  <div class="py-3">Item 2</div>
  <div class="py-3">Item 3</div>
</div>

4.8 Shadow Utilities

<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 shadow</div>
<div class="shadow-2xl">2XL shadow</div>
<div class="shadow-none">No shadow</div>

<!-- Colored shadows -->
<div class="shadow-lg shadow-blue-500/25">Blue tinted shadow</div>

<!-- Inset shadows -->
<div class="inset-shadow-sm">Small inset shadow</div>

4.9 Sizing Utilities

Width

<div class="w-full">100% width</div>
<div class="w-1/2">50% width</div>
<div class="w-1/3">33.33% width</div>
<div class="w-2/3">66.67% width</div>
<div class="w-1/4">25% width</div>
<div class="w-64">16rem width</div>
<div class="w-screen">100vw width</div>
<div class="w-auto">Auto width</div>
<div class="w-fit">Fit-content width</div>
<div class="w-min">Min-content width</div>
<div class="w-max">Max-content width</div>

<!-- Min/Max width -->
<div class="min-w-0">Min-width 0</div>
<div class="min-w-full">Min-width 100%</div>
<div class="max-w-sm">Max-width 24rem</div>
<div class="max-w-md">Max-width 28rem</div>
<div class="max-w-lg">Max-width 32rem</div>
<div class="max-w-xl">Max-width 36rem</div>
<div class="max-w-2xl">Max-width 42rem</div>
<div class="max-w-prose">Max-width 65ch</div>
<div class="max-w-none">No max-width</div>

Height

<div class="h-full">100% height</div>
<div class="h-screen">100vh height</div>
<div class="h-dvh">100dvh (dynamic viewport height)</div>
<div class="h-svh">100svh (small viewport height)</div>
<div class="h-lvh">100lvh (large viewport height)</div>
<div class="h-64">16rem height</div>
<div class="h-auto">Auto height</div>
<div class="h-fit">Fit-content height</div>

<!-- Min/Max height -->
<div class="min-h-screen">Min-height 100vh</div>
<div class="min-h-full">Min-height 100%</div>
<div class="max-h-96">Max-height 24rem</div>

Size (Width + Height)

<div class="size-8">2rem width and height</div>
<div class="size-12">3rem width and height</div>
<div class="size-full">100% width and height</div>

4.10 Variants (Responsive, State, Dark Mode)

Variants are modifiers you prepend to any utility class with a colon :. They apply the utility conditionally.

Responsive Variants

Tailwind uses a mobile-first breakpoint system. Unprefixed utilities apply at all screen sizes. Prefixed utilities apply at that breakpoint and above.

Default breakpoints:

Breakpoint Min Width CSS
sm: 40rem (640px) @media (min-width: 40rem)
md: 48rem (768px) @media (min-width: 48rem)
lg: 64rem (1024px) @media (min-width: 64rem)
xl: 80rem (1280px) @media (min-width: 80rem)
2xl: 96rem (1536px) @media (min-width: 96rem)
<!-- Single column on mobile, two columns on medium, three on large -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
  <div>Card 1</div>
  <div>Card 2</div>
  <div>Card 3</div>
</div>

<!-- Hidden on mobile, visible on large screens -->
<nav class="hidden lg:flex gap-6">
  <a href="#">Home</a>
  <a href="#">About</a>
</nav>

<!-- Different padding at different breakpoints -->
<div class="p-4 md:p-8 lg:p-12">
  Responsive padding
</div>

<!-- Different text size at breakpoints -->
<h1 class="text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-bold">
  Responsive heading
</h1>

Hover, Focus, and Other State Variants

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

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

<!-- Focus-visible (keyboard focus only) -->
<button class="focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:outline-none">
  Keyboard focus ring
</button>

<!-- Active -->
<button class="bg-blue-500 active:bg-blue-800">Press me</button>

<!-- Disabled -->
<button class="bg-blue-500 disabled:bg-gray-300 disabled:cursor-not-allowed" disabled>
  Disabled
</button>

<!-- First/Last child -->
<ul>
  <li class="first:pt-0 last:pb-0 py-2 border-b last:border-b-0">Item</li>
</ul>

<!-- Odd/Even -->
<tr class="odd:bg-gray-50 even:bg-white">
  <td>Row content</td>
</tr>

<!-- Required/Invalid/Valid -->
<input class="invalid:border-red-500 valid:border-green-500" required>

<!-- Checked -->
<input type="checkbox" class="checked:bg-blue-500">

<!-- Placeholder shown -->
<input class="placeholder-shown:border-gray-300">

Group and Peer Variants

Style children based on parent state:

<!-- Group hover -->
<a class="group block p-6 bg-white rounded-lg shadow hover:shadow-lg transition">
  <h3 class="text-gray-900 group-hover:text-blue-600 font-semibold">
    Card Title
  </h3>
  <p class="text-gray-500 group-hover:text-gray-700">
    Card description text
  </p>
</a>

<!-- Group focus -->
<label class="group">
  <input type="text" class="border rounded px-3 py-2">
  <span class="text-gray-400 group-focus-within:text-blue-500">
    Helper text
  </span>
</label>

<!-- Named groups -->
<div class="group/sidebar">
  <button class="group-hover/sidebar:bg-gray-100">Toggle</button>
</div>

Style siblings based on sibling state:

<!-- Peer (sibling-based styling) -->
<div>
  <input type="email" class="peer" placeholder="Email">
  <p class="hidden peer-invalid:block text-red-500 text-sm mt-1">
    Please enter a valid email address.
  </p>
</div>

Dark Mode

<!-- Dark mode variants -->
<div class="bg-white dark:bg-gray-900">
  <h1 class="text-gray-900 dark:text-white">Heading</h1>
  <p class="text-gray-600 dark:text-gray-300">Body text</p>
</div>

<!-- Card with dark mode -->
<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg p-6 shadow dark:shadow-gray-900/20">
  <h3 class="text-gray-900 dark:text-gray-100 font-semibold">Card</h3>
  <p class="text-gray-500 dark:text-gray-400 mt-2">Card content</p>
</div>

Dark mode uses the prefers-color-scheme media query by default.

<div class="print:hidden">Hidden when printing</div>
<div class="hidden print:block">Visible only when printing</div>

Motion Variants

<!-- Respect user's motion preferences -->
<div class="transition-transform motion-safe:hover:scale-105 motion-reduce:transition-none">
  Animated on hover (unless user prefers reduced motion)
</div>

Portrait and Landscape

<div class="portrait:hidden">Hidden in portrait orientation</div>
<div class="landscape:hidden">Hidden in landscape orientation</div>

RTL and LTR

<div class="rtl:text-right ltr:text-left">
  Direction-aware alignment
</div>

Container Queries

<div class="@container">
  <div class="@sm:flex @lg:grid @lg:grid-cols-2 gap-4">
    Container-query responsive layout
  </div>
</div>

Stacking Variants

Variants can be stacked. They read left to right:

<!-- Dark mode + hover + medium breakpoint -->
<button class="md:dark:hover:bg-blue-800">
  Hover on medium+ screens in dark mode
</button>

<!-- Focus-within on large screens -->
<div class="lg:focus-within:ring-2 lg:focus-within:ring-blue-500">
  Focus ring on large screens
</div>

4.11 Arbitrary Values

When the default utilities do not provide the exact value you need, use square bracket notation:

<!-- Arbitrary values -->
<div class="w-[137px]">Exact width</div>
<div class="h-[calc(100vh-4rem)]">Calculated height</div>
<div class="bg-[#1da1f2]">Exact hex color</div>
<div class="text-[22px]">Exact font size</div>
<div class="grid-cols-[200px_1fr_200px]">Custom grid template</div>
<div class="top-[117px]">Exact positioning</div>
<div class="p-[clamp(1rem,5vw,3rem)]">Clamped padding</div>

<!-- Arbitrary properties (for any CSS property) -->
<div class="[mask-type:luminance]">Arbitrary CSS property</div>
<div class="[--my-var:16px]">Set a custom property</div>

<!-- Arbitrary variants -->
<div class="[&>p]:text-gray-600">Direct child paragraphs</div>
<div class="[@supports(display:grid)]:grid">Supports query</div>
<div class="[@media(min-width:900px)]:flex">Custom media query</div>

Underscores in arbitrary values are treated as spaces:

<!-- Underscore = space -->
<div class="bg-[url('/image_with_space.jpg')]">Background image</div>
<div class="grid-cols-[1fr_auto_1fr]">Grid columns: 1fr auto 1fr</div>

To use an actual underscore, escape it with a backslash:

<div class="bg-[url('/image\_name.jpg')]">Literal underscore in value</div>

4.12 The @apply Directive

The @apply directive lets you use utility classes inside your CSS:

.btn {
  @apply px-4 py-2 rounded-lg font-semibold text-sm transition-colors;
}

.btn-primary {
  @apply btn bg-blue-500 text-white hover:bg-blue-700;
}

.btn-secondary {
  @apply btn bg-gray-200 text-gray-800 hover:bg-gray-300;
}
/* Card component */
.card {
  @apply bg-white rounded-xl shadow-md p-6 border border-gray-100;
}

.card-title {
  @apply text-xl font-semibold text-gray-900 mb-2;
}

.card-body {
  @apply text-gray-600 leading-relaxed;
}

@apply Limitations

  • Cannot use @apply inside @keyframes blocks. Attempting to do so produces: You cannot use @apply inside @keyframes.
  • If you reference a utility that does not exist, you get: Cannot apply unknown utility class '{candidate}'
  • If your project uses a prefix and you forget it: Cannot apply unprefixed utility class '{candidate}'. Did you mean '{prefix}:{candidate}'?
  • Circular references produce: Cannot apply utility class '{candidate}' because it creates a circular dependency.

Note

While @apply is useful for extracting repeated patterns, Tailwind's recommended approach is to use component abstractions in your framework (React components, Vue components, partials, etc.) rather than creating CSS classes with @apply. Reserve @apply for cases where you cannot use component abstractions, such as styling third-party markup or CMS content.

4.13 Custom Utilities with @utility

Define entirely new utility classes:

@utility content-auto {
  content-visibility: auto;
}

@utility scrollbar-hidden {
  scrollbar-width: none;
  &::-webkit-scrollbar {
    display: none;
  }
}

@utility text-balance {
  text-wrap: balance;
}

These become available as regular utility classes:

<div class="content-auto">Lazy-rendered content</div>
<div class="scrollbar-hidden overflow-y-auto">No visible scrollbar</div>
<h1 class="text-balance text-4xl">Balanced headline text</h1>

Custom utilities support variants:

<div class="md:content-auto hover:content-auto">
  Variant-aware custom utility
</div>

Functional Utilities with Values

@utility tab-size-* {
  tab-size: --value(--tab-size-*);
}

This generates tab-size-2, tab-size-4, tab-size-8, etc., from your theme.

4.14 Custom Variants with @variant

Define new variants for conditional styling.

Selector-Based Variant

@variant pointer-coarse (@media (pointer: coarse));
@variant pointer-fine (@media (pointer: fine));

Usage:

<button class="pointer-coarse:p-4 pointer-fine:p-2">
  Larger padding on touch devices
</button>

Complex Selector Variants

@variant hocus (&:hover, &:focus);
<button class="hocus:bg-blue-600">Hover or focus</button>

4.15 Transition and Animation

<!-- Basic transition -->
<button class="transition-colors duration-200 hover:bg-blue-600">
  Smooth color change
</button>

<!-- Multiple transition properties -->
<div class="transition-all duration-300 ease-in-out hover:scale-105 hover:shadow-lg">
  Scale and shadow on hover
</div>

<!-- Specific transition durations -->
<div class="transition duration-75">75ms</div>
<div class="transition duration-100">100ms</div>
<div class="transition duration-150">150ms (default)</div>
<div class="transition duration-200">200ms</div>
<div class="transition duration-300">300ms</div>
<div class="transition duration-500">500ms</div>
<div class="transition duration-700">700ms</div>
<div class="transition duration-1000">1000ms</div>

<!-- Transition delay -->
<div class="transition delay-150 hover:bg-blue-500">150ms delay</div>

<!-- Easing functions -->
<div class="transition ease-linear">Linear</div>
<div class="transition ease-in">Ease in</div>
<div class="transition ease-out">Ease out</div>
<div class="transition ease-in-out">Ease in-out</div>

<!-- Built-in animations -->
<div class="animate-spin">Spinning</div>
<div class="animate-ping">Pinging</div>
<div class="animate-pulse">Pulsing</div>
<div class="animate-bounce">Bouncing</div>

4.16 Transforms

<!-- Scale -->
<div class="scale-95">95% scale</div>
<div class="hover:scale-105">105% on hover</div>
<div class="scale-x-110 scale-y-90">Different X/Y scale</div>

<!-- Rotate -->
<div class="rotate-45">45 degrees</div>
<div class="-rotate-12">-12 degrees</div>
<div class="hover:rotate-6">Rotate on hover</div>

<!-- Translate -->
<div class="translate-x-4">Move right 1rem</div>
<div class="-translate-y-2">Move up 0.5rem</div>
<div class="hover:translate-y-1">Move down on hover</div>

<!-- Skew -->
<div class="skew-x-3">Skew X 3 degrees</div>
<div class="skew-y-6">Skew Y 6 degrees</div>

<!-- Transform origin -->
<div class="origin-top-left rotate-12">Rotate from top-left corner</div>
<div class="origin-center scale-150">Scale from center</div>

4.17 Filters and Effects

<!-- Blur -->
<div class="blur-sm">Slight blur</div>
<div class="blur-md">Medium blur</div>
<div class="blur-lg">Large blur</div>
<div class="blur-none">No blur</div>

<!-- Brightness -->
<img class="brightness-50" src="photo.jpg">
<img class="brightness-110" src="photo.jpg">

<!-- Contrast -->
<img class="contrast-125" src="photo.jpg">

<!-- Grayscale -->
<img class="grayscale" src="photo.jpg">
<img class="grayscale-0" src="photo.jpg">

<!-- Hue rotate -->
<img class="hue-rotate-90" src="photo.jpg">

<!-- Invert -->
<img class="invert" src="photo.jpg">

<!-- Saturate -->
<img class="saturate-150" src="photo.jpg">

<!-- Sepia -->
<img class="sepia" src="photo.jpg">

<!-- Drop shadow -->
<img class="drop-shadow-lg" src="icon.png">
<img class="drop-shadow-xl" src="icon.png">

<!-- Backdrop blur (glassmorphism) -->
<div class="backdrop-blur-md bg-white/30">
  Frosted glass effect
</div>

<!-- Backdrop brightness -->
<div class="backdrop-brightness-75">Darkened backdrop</div>

<!-- Opacity -->
<div class="opacity-50">50% opacity</div>
<div class="opacity-0">Invisible (but in DOM)</div>
<div class="hover:opacity-100 transition-opacity">Fade in on hover</div>

<!-- Mix blend mode -->
<div class="mix-blend-multiply">Multiply blend</div>
<div class="mix-blend-screen">Screen blend</div>
<div class="mix-blend-overlay">Overlay blend</div>

4.18 Overflow and Scroll

<!-- Overflow -->
<div class="overflow-auto">Auto scrollbar when needed</div>
<div class="overflow-hidden">Hidden overflow</div>
<div class="overflow-scroll">Always show scrollbar</div>
<div class="overflow-x-auto">Horizontal scroll when needed</div>
<div class="overflow-y-auto">Vertical scroll when needed</div>
<div class="overflow-visible">Visible overflow</div>
<div class="overflow-clip">Clip overflow (no scroll)</div>

<!-- Scroll behavior -->
<div class="scroll-smooth">Smooth scrolling</div>

<!-- Scroll snap -->
<div class="snap-x snap-mandatory overflow-x-auto flex gap-4">
  <div class="snap-center shrink-0 w-80">Slide 1</div>
  <div class="snap-center shrink-0 w-80">Slide 2</div>
  <div class="snap-center shrink-0 w-80">Slide 3</div>
</div>

<!-- Scroll padding/margin -->
<div class="scroll-pt-16">16rem scroll padding-top</div>
<div class="scroll-mt-4">4 scroll margin-top</div>

<!-- Overscroll behavior -->
<div class="overscroll-contain">Contain overscroll</div>
<div class="overscroll-none">No overscroll</div>

4.19 Interactivity

<!-- Cursor -->
<div class="cursor-pointer">Pointer cursor</div>
<div class="cursor-not-allowed">Not-allowed cursor</div>
<div class="cursor-wait">Wait cursor</div>
<div class="cursor-grab">Grab cursor</div>
<div class="cursor-move">Move cursor</div>
<div class="cursor-text">Text cursor</div>
<div class="cursor-default">Default cursor</div>

<!-- Pointer events -->
<div class="pointer-events-none">Click-through</div>
<div class="pointer-events-auto">Normal pointer events</div>

<!-- User select -->
<p class="select-none">Cannot be selected</p>
<p class="select-text">Can be selected</p>
<p class="select-all">Select all on click</p>

<!-- Touch action -->
<div class="touch-none">Disable touch gestures</div>
<div class="touch-pan-x">Allow horizontal panning only</div>
<div class="touch-pan-y">Allow vertical panning only</div>
<div class="touch-manipulation">Allow pan and zoom only</div>

<!-- Resize -->
<textarea class="resize">Resizable both ways</textarea>
<textarea class="resize-x">Horizontal resize only</textarea>
<textarea class="resize-y">Vertical resize only</textarea>
<textarea class="resize-none">No resize</textarea>

<!-- Appearance -->
<select class="appearance-none">Remove native appearance</select>

<!-- Caret color -->
<input class="caret-blue-500" type="text">

<!-- Accent color (for checkboxes, radios, range) -->
<input type="checkbox" class="accent-pink-500">
<input type="range" class="accent-green-600">

<!-- Will-change (performance hint) -->
<div class="will-change-transform">Optimize for transform changes</div>
<div class="will-change-scroll">Optimize for scroll changes</div>

4.20 Tables

<table class="w-full border-collapse">
  <thead>
    <tr class="bg-gray-50 text-left">
      <th class="px-4 py-3 text-sm font-semibold text-gray-600 border-b">Name</th>
      <th class="px-4 py-3 text-sm font-semibold text-gray-600 border-b">Status</th>
      <th class="px-4 py-3 text-sm font-semibold text-gray-600 border-b">Role</th>
    </tr>
  </thead>
  <tbody class="divide-y divide-gray-200">
    <tr class="hover:bg-gray-50">
      <td class="px-4 py-3 text-sm text-gray-900">Jane Cooper</td>
      <td class="px-4 py-3">
        <span class="inline-flex items-center rounded-full bg-green-50 px-2 py-1 text-xs font-medium text-green-700 ring-1 ring-green-600/20 ring-inset">Active</span>
      </td>
      <td class="px-4 py-3 text-sm text-gray-500">Admin</td>
    </tr>
    <tr class="hover:bg-gray-50">
      <td class="px-4 py-3 text-sm text-gray-900">John Smith</td>
      <td class="px-4 py-3">
        <span class="inline-flex items-center rounded-full bg-yellow-50 px-2 py-1 text-xs font-medium text-yellow-700 ring-1 ring-yellow-600/20 ring-inset">Pending</span>
      </td>
      <td class="px-4 py-3 text-sm text-gray-500">Editor</td>
    </tr>
  </tbody>
</table>

<!-- Table layout -->
<table class="table-fixed w-full">Fixed layout</table>
<table class="table-auto">Auto layout</table>

<!-- Caption side -->
<table>
  <caption class="caption-bottom text-sm text-gray-500">Table caption</caption>
</table>

4.21 SVG

<!-- Fill -->
<svg class="fill-current text-blue-500">...</svg>
<svg class="fill-blue-500">...</svg>
<svg class="fill-none">...</svg>

<!-- Stroke -->
<svg class="stroke-current text-gray-400">...</svg>
<svg class="stroke-blue-500">...</svg>
<svg class="stroke-2">2px stroke width</svg>
<svg class="stroke-[3px]">3px stroke width</svg>

4.22 Accessibility

<!-- Screen reader only (visually hidden but accessible) -->
<span class="sr-only">Screen reader text</span>

<!-- Undo sr-only (useful with focus) -->
<a class="sr-only focus:not-sr-only focus:absolute focus:p-4 focus:bg-white">
  Skip to content
</a>

<!-- Focus management -->
<button class="focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500">
  Keyboard-accessible focus ring
</button>

<!-- Forced colors (Windows high contrast) -->
<div class="forced-colors:border forced-colors:border-current">
  High contrast border
</div>

5. Common Tasks

5.1 Building a Responsive Navigation Bar

<nav class="bg-white shadow-sm border-b border-gray-100">
  <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">
        MyApp
      </a>

      <!-- Desktop navigation -->
      <div class="hidden md:flex items-center gap-8">
        <a href="#" class="text-sm font-medium text-gray-500 hover:text-gray-900 transition-colors">
          Features
        </a>
        <a href="#" class="text-sm font-medium text-gray-500 hover:text-gray-900 transition-colors">
          Pricing
        </a>
        <a href="#" class="text-sm font-medium text-gray-500 hover:text-gray-900 transition-colors">
          Docs
        </a>
        <a href="#" class="text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 px-4 py-2 rounded-lg transition-colors">
          Sign Up
        </a>
      </div>

      <!-- Mobile menu button -->
      <button class="md:hidden p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100">
        <svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"/>
        </svg>
      </button>
    </div>
  </div>

  <!-- Mobile menu (toggle visibility with JS) -->
  <div class="md:hidden border-t border-gray-100">
    <div class="px-4 py-3 space-y-2">
      <a href="#" class="block px-3 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 rounded-md">Features</a>
      <a href="#" class="block px-3 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 rounded-md">Pricing</a>
      <a href="#" class="block px-3 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 rounded-md">Docs</a>
      <a href="#" class="block px-3 py-2 text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 rounded-md text-center">Sign Up</a>
    </div>
  </div>
</nav>

5.2 Building a Card Component

<!-- Basic card -->
<div class="bg-white rounded-xl shadow-md overflow-hidden max-w-md">
  <img class="w-full h-48 object-cover" src="image.jpg" alt="Card image">
  <div class="p-6">
    <span class="text-xs font-semibold uppercase tracking-wider text-blue-600">Category</span>
    <h3 class="mt-2 text-xl font-bold text-gray-900">Card Title</h3>
    <p class="mt-2 text-gray-600 line-clamp-3">
      Card description text that can be truncated to three lines maximum.
    </p>
    <div class="mt-4 flex items-center justify-between">
      <span class="text-sm text-gray-500">5 min read</span>
      <a href="#" class="text-sm font-semibold text-blue-600 hover:text-blue-800">
        Read more &rarr;
      </a>
    </div>
  </div>
</div>

<!-- Horizontal card -->
<div class="flex bg-white rounded-xl shadow-md overflow-hidden max-w-2xl">
  <img class="w-48 object-cover shrink-0" src="image.jpg" alt="">
  <div class="p-6">
    <h3 class="text-lg font-bold text-gray-900">Horizontal Card</h3>
    <p class="mt-2 text-gray-600">Description text here.</p>
  </div>
</div>

5.3 Building Form Elements

<!-- Text input -->
<div>
  <label for="email" class="block text-sm font-medium text-gray-700 mb-1">
    Email address
  </label>
  <input
    id="email"
    type="email"
    class="w-full px-3 py-2 border border-gray-300 rounded-lg shadow-sm
           placeholder-gray-400
           focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500
           disabled:bg-gray-50 disabled:text-gray-500 disabled:cursor-not-allowed
           invalid:border-red-500 invalid:focus:ring-red-500"
    placeholder="[email removed]"
  >
</div>

<!-- Select -->
<div>
  <label class="block text-sm font-medium text-gray-700 mb-1">Country</label>
  <select class="w-full px-3 py-2 border border-gray-300 rounded-lg shadow-sm
                 bg-white focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
    <option>United States</option>
    <option>Canada</option>
    <option>Mexico</option>
  </select>
</div>

<!-- Textarea -->
<div>
  <label class="block text-sm font-medium text-gray-700 mb-1">Message</label>
  <textarea
    rows="4"
    class="w-full px-3 py-2 border border-gray-300 rounded-lg shadow-sm
           placeholder-gray-400 resize-y
           focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
    placeholder="Write your message..."
  ></textarea>
</div>

<!-- Checkbox -->
<label class="flex items-center gap-3">
  <input type="checkbox" class="w-4 h-4 rounded border-gray-300 text-blue-600 accent-blue-600
                                 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2">
  <span class="text-sm text-gray-700">I agree to the terms</span>
</label>

<!-- Radio group -->
<fieldset class="space-y-3">
  <legend class="text-sm font-medium text-gray-700">Plan</legend>
  <label class="flex items-center gap-3">
    <input type="radio" name="plan" class="w-4 h-4 border-gray-300 text-blue-600 accent-blue-600">
    <span class="text-sm text-gray-700">Free</span>
  </label>
  <label class="flex items-center gap-3">
    <input type="radio" name="plan" class="w-4 h-4 border-gray-300 text-blue-600 accent-blue-600">
    <span class="text-sm text-gray-700">Pro — $9/month</span>
  </label>
</fieldset>

<!-- Toggle switch pattern -->
<button
  role="switch"
  aria-checked="false"
  class="relative inline-flex h-6 w-11 items-center rounded-full
         bg-gray-200 transition-colors
         aria-checked:bg-blue-600"
>
  <span class="inline-block h-4 w-4 rounded-full bg-white shadow transform transition-transform
               translate-x-1 aria-checked:translate-x-6"></span>
</button>

5.4 Building a Hero Section

<section class="relative bg-gray-900 overflow-hidden">
  <!-- Background pattern -->
  <div class="absolute inset-0 bg-gradient-to-br from-blue-600/20 to-purple-600/20"></div>

  <div class="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-24 sm:py-32 lg:py-40">
    <div class="max-w-3xl">
      <span class="inline-flex items-center rounded-full bg-blue-500/10 px-3 py-1 text-sm font-medium text-blue-400 ring-1 ring-blue-500/20 ring-inset mb-6">
        What's new &mdash; v4.2 released
      </span>
      <h1 class="text-4xl sm:text-5xl lg:text-6xl font-bold text-white tracking-tight leading-tight">
        Build modern websites without ever leaving your HTML
      </h1>
      <p class="mt-6 text-lg sm:text-xl text-gray-300 leading-relaxed max-w-2xl">
        A utility-first CSS framework packed with classes that can be composed
        to build any design, directly in your markup.
      </p>
      <div class="mt-10 flex flex-wrap gap-4">
        <a href="#" class="inline-flex items-center px-6 py-3 text-sm font-semibold text-white bg-blue-600 hover:bg-blue-700 rounded-lg transition-colors shadow-lg shadow-blue-600/25">
          Get Started
        </a>
        <a href="#" class="inline-flex items-center px-6 py-3 text-sm font-semibold text-gray-300 bg-white/10 hover:bg-white/20 rounded-lg transition-colors ring-1 ring-white/20">
          Documentation &rarr;
        </a>
      </div>
    </div>
  </div>
</section>

5.5 Building a Pricing Table

<div class="grid grid-cols-1 md:grid-cols-3 gap-8 max-w-5xl mx-auto px-4">
  <!-- Free tier -->
  <div class="bg-white rounded-2xl border border-gray-200 p-8">
    <h3 class="text-lg font-semibold text-gray-900">Free</h3>
    <p class="mt-2 text-sm text-gray-500">For individuals getting started.</p>
    <p class="mt-6">
      <span class="text-4xl font-bold text-gray-900">$0</span>
      <span class="text-sm text-gray-500">/month</span>
    </p>
    <a href="#" class="mt-8 block w-full py-2.5 text-center text-sm font-semibold text-blue-600 bg-blue-50 hover:bg-blue-100 rounded-lg transition-colors">
      Get started
    </a>
    <ul class="mt-8 space-y-3">
      <li class="flex items-center gap-3 text-sm text-gray-600">
        <svg class="w-5 h-5 text-green-500 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
        5 projects
      </li>
      <li class="flex items-center gap-3 text-sm text-gray-600">
        <svg class="w-5 h-5 text-green-500 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
        Community support
      </li>
    </ul>
  </div>

  <!-- Pro tier (highlighted) -->
  <div class="bg-blue-600 rounded-2xl p-8 shadow-xl shadow-blue-600/20 ring-2 ring-blue-600 relative">
    <span class="absolute -top-4 left-1/2 -translate-x-1/2 bg-blue-600 text-white text-xs font-bold uppercase tracking-wider px-3 py-1 rounded-full">
      Popular
    </span>
    <h3 class="text-lg font-semibold text-white">Pro</h3>
    <p class="mt-2 text-sm text-blue-200">For professionals and small teams.</p>
    <p class="mt-6">
      <span class="text-4xl font-bold text-white">$29</span>
      <span class="text-sm text-blue-200">/month</span>
    </p>
    <a href="#" class="mt-8 block w-full py-2.5 text-center text-sm font-semibold text-blue-600 bg-white hover:bg-blue-50 rounded-lg transition-colors">
      Get started
    </a>
    <ul class="mt-8 space-y-3">
      <li class="flex items-center gap-3 text-sm text-blue-100">
        <svg class="w-5 h-5 text-blue-300 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
        Unlimited projects
      </li>
      <li class="flex items-center gap-3 text-sm text-blue-100">
        <svg class="w-5 h-5 text-blue-300 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
        Priority support
      </li>
      <li class="flex items-center gap-3 text-sm text-blue-100">
        <svg class="w-5 h-5 text-blue-300 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
        Advanced analytics
      </li>
    </ul>
  </div>

  <!-- Enterprise tier -->
  <div class="bg-white rounded-2xl border border-gray-200 p-8">
    <h3 class="text-lg font-semibold text-gray-900">Enterprise</h3>
    <p class="mt-2 text-sm text-gray-500">For large organizations.</p>
    <p class="mt-6">
      <span class="text-4xl font-bold text-gray-900">$99</span>
      <span class="text-sm text-gray-500">/month</span>
    </p>
    <a href="#" class="mt-8 block w-full py-2.5 text-center text-sm font-semibold text-blue-600 bg-blue-50 hover:bg-blue-100 rounded-lg transition-colors">
      Contact sales
    </a>
    <ul class="mt-8 space-y-3">
      <li class="flex items-center gap-3 text-sm text-gray-600">
        <svg class="w-5 h-5 text-green-500 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
        Everything in Pro
      </li>
      <li class="flex items-center gap-3 text-sm text-gray-600">
        <svg class="w-5 h-5 text-green-500 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
        SSO & SAML
      </li>
      <li class="flex items-center gap-3 text-sm text-gray-600">
        <svg class="w-5 h-5 text-green-500 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
        Dedicated support
      </li>
    </ul>
  </div>
</div>

5.6 Building a Modal / Dialog

<!-- Backdrop -->
<div class="fixed inset-0 z-50 flex items-center justify-center">
  <!-- Overlay -->
  <div class="fixed inset-0 bg-black/50 backdrop-blur-sm"></div>

  <!-- Modal -->
  <div class="relative bg-white rounded-2xl shadow-2xl max-w-md w-full mx-4 p-6 z-10">
    <!-- Close button -->
    <button class="absolute top-4 right-4 text-gray-400 hover:text-gray-600">
      <svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
      </svg>
    </button>

    <h2 class="text-lg font-semibold text-gray-900">Delete project?</h2>
    <p class="mt-2 text-sm text-gray-500">
      This action cannot be undone. All project data will be permanently removed.
    </p>

    <div class="mt-6 flex gap-3 justify-end">
      <button class="px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors">
        Cancel
      </button>
      <button class="px-4 py-2 text-sm font-medium text-white bg-red-600 rounded-lg hover:bg-red-700 transition-colors">
        Delete
      </button>
    </div>
  </div>
</div>

5.7 Building a Sidebar Layout

<div class="flex h-screen">
  <!-- Sidebar -->
  <aside class="w-64 shrink-0 bg-gray-900 text-white flex flex-col">
    <div class="p-6">
      <h2 class="text-lg font-bold">Dashboard</h2>
    </div>
    <nav class="flex-1 px-3 space-y-1 overflow-y-auto">
      <a href="#" class="flex items-center gap-3 px-3 py-2 text-sm font-medium text-white bg-gray-800 rounded-lg">
        <svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"/></svg>
        Home
      </a>
      <a href="#" class="flex items-center gap-3 px-3 py-2 text-sm font-medium text-gray-400 hover:text-white hover:bg-gray-800 rounded-lg transition-colors">
        <svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"/></svg>
        Analytics
      </a>
      <a href="#" class="flex items-center gap-3 px-3 py-2 text-sm font-medium text-gray-400 hover:text-white hover:bg-gray-800 rounded-lg transition-colors">
        <svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.066 2.573c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.573 1.066c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.066-2.573c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"/><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/></svg>
        Settings
      </a>
    </nav>
    <div class="p-4 border-t border-gray-800">
      <div class="flex items-center gap-3">
        <div class="w-8 h-8 rounded-full bg-gray-700"></div>
        <div>
          <p class="text-sm font-medium">Jane Smith</p>
          <p class="text-xs text-gray-400">[email removed]</p>
        </div>
      </div>
    </div>
  </aside>

  <!-- Main content -->
  <main class="flex-1 overflow-y-auto bg-gray-50">
    <div class="p-8">
      <h1 class="text-2xl font-bold text-gray-900">Dashboard</h1>
      <!-- Content here -->
    </div>
  </main>
</div>

5.8 Building a Notification / Toast

<!-- Success toast -->
<div class="flex items-center gap-3 bg-white rounded-lg shadow-lg ring-1 ring-black/5 p-4 max-w-sm">
  <div class="shrink-0 w-10 h-10 bg-green-100 rounded-full flex items-center justify-center">
    <svg class="w-5 h-5 text-green-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
      <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
    </svg>
  </div>
  <div class="flex-1 min-w-0">
    <p class="text-sm font-semibold text-gray-900">Successfully saved!</p>
    <p class="text-sm text-gray-500 mt-0.5">Your changes have been saved.</p>
  </div>
  <button class="shrink-0 text-gray-400 hover:text-gray-600">
    <svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
      <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
    </svg>
  </button>
</div>

<!-- Error alert -->
<div class="bg-red-50 border border-red-200 rounded-lg p-4">
  <div class="flex items-start gap-3">
    <svg class="w-5 h-5 text-red-500 mt-0.5 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
      <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
    </svg>
    <div>
      <h3 class="text-sm font-semibold text-red-800">Error occurred</h3>
      <p class="text-sm text-red-700 mt-1">Something went wrong. Please try again.</p>
    </div>
  </div>
</div>

<!-- Warning alert -->
<div class="bg-yellow-50 border border-yellow-200 rounded-lg p-4">
  <div class="flex items-start gap-3">
    <svg class="w-5 h-5 text-yellow-500 mt-0.5 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
      <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/>
    </svg>
    <div>
      <h3 class="text-sm font-semibold text-yellow-800">Warning</h3>
      <p class="text-sm text-yellow-700 mt-1">Your trial expires in 3 days.</p>
    </div>
  </div>
</div>

<!-- Info alert -->
<div class="bg-blue-50 border border-blue-200 rounded-lg p-4">
  <div class="flex items-start gap-3">
    <svg class="w-5 h-5 text-blue-500 mt-0.5 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
      <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
    </svg>
    <div>
      <h3 class="text-sm font-semibold text-blue-800">Information</h3>
      <p class="text-sm text-blue-700 mt-1">A new version is available.</p>
    </div>
  </div>
</div>

5.9 Building a Badge / Tag System

<!-- Solid badges -->
<span class="inline-flex items-center rounded-full bg-blue-100 px-2.5 py-0.5 text-xs font-medium text-blue-700">
  Badge
</span>
<span class="inline-flex items-center rounded-full bg-green-100 px-2.5 py-0.5 text-xs font-medium text-green-700">
  Active
</span>
<span class="inline-flex items-center rounded-full bg-red-100 px-2.5 py-0.5 text-xs font-medium text-red-700">
  Error
</span>
<span class="inline-flex items-center rounded-full bg-yellow-100 px-2.5 py-0.5 text-xs font-medium text-yellow-700">
  Pending
</span>
<span class="inline-flex items-center rounded-full bg-gray-100 px-2.5 py-0.5 text-xs font-medium text-gray-700">
  Draft
</span>

<!-- Ring badges -->
<span class="inline-flex items-center rounded-full bg-blue-50 px-2.5 py-0.5 text-xs font-medium text-blue-700 ring-1 ring-blue-600/20 ring-inset">
  Ring Badge
</span>

<!-- Dot badges -->
<span class="inline-flex items-center gap-1.5 rounded-full bg-green-50 px-2.5 py-0.5 text-xs font-medium text-green-700">
  <span class="w-1.5 h-1.5 rounded-full bg-green-500"></span>
  Online
</span>

<!-- Removable tags -->
<span class="inline-flex items-center gap-1 rounded-full bg-blue-100 px-3 py-1 text-sm text-blue-700">
  React
  <button class="ml-1 hover:text-blue-900">
    <svg class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
      <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
    </svg>
  </button>
</span>
<footer class="bg-gray-900 text-gray-300">
  <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
    <div class="grid grid-cols-2 md:grid-cols-4 gap-8">
      <div>
        <h3 class="text-sm font-semibold text-white uppercase tracking-wider">Product</h3>
        <ul class="mt-4 space-y-3">
          <li><a href="#" class="text-sm hover:text-white transition-colors">Features</a></li>
          <li><a href="#" class="text-sm hover:text-white transition-colors">Pricing</a></li>
          <li><a href="#" class="text-sm hover:text-white transition-colors">Changelog</a></li>
          <li><a href="#" class="text-sm hover:text-white transition-colors">Docs</a></li>
        </ul>
      </div>
      <div>
        <h3 class="text-sm font-semibold text-white uppercase tracking-wider">Company</h3>
        <ul class="mt-4 space-y-3">
          <li><a href="#" class="text-sm hover:text-white transition-colors">About</a></li>
          <li><a href="#" class="text-sm hover:text-white transition-colors">Blog</a></li>
          <li><a href="#" class="text-sm hover:text-white transition-colors">Careers</a></li>
        </ul>
      </div>
      <div>
        <h3 class="text-sm font-semibold text-white uppercase tracking-wider">Legal</h3>
        <ul class="mt-4 space-y-3">
          <li><a href="#" class="text-sm hover:text-white transition-colors">Privacy</a></li>
          <li><a href="#" class="text-sm hover:text-white transition-colors">Terms</a></li>
        </ul>
      </div>
      <div>
        <h3 class="text-sm font-semibold text-white uppercase tracking-wider">Connect</h3>
        <ul class="mt-4 space-y-3">
          <li><a href="#" class="text-sm hover:text-white transition-colors">Twitter</a></li>
          <li><a href="#" class="text-sm hover:text-white transition-colors">GitHub</a></li>
          <li><a href="#" class="text-sm hover:text-white transition-colors">Discord</a></li>
        </ul>
      </div>
    </div>
    <div class="mt-12 pt-8 border-t border-gray-800 text-center">
      <p class="text-sm text-gray-400">&copy; 2026 MyApp. All rights reserved.</p>
    </div>
  </div>
</footer>

5.11 Building an Avatar Group

<div class="flex -space-x-2">
  <img class="w-10 h-10 rounded-full ring-2 ring-white" src="avatar1.jpg" alt="User 1">
  <img class="w-10 h-10 rounded-full ring-2 ring-white" src="avatar2.jpg" alt="User 2">
  <img class="w-10 h-10 rounded-full ring-2 ring-white" src="avatar3.jpg" alt="User 3">
  <img class="w-10 h-10 rounded-full ring-2 ring-white" src="avatar4.jpg" alt="User 4">
  <span class="flex items-center justify-center w-10 h-10 rounded-full ring-2 ring-white bg-gray-200 text-xs font-medium text-gray-600">
    +5
  </span>
</div>

5.12 Building a Breadcrumb

<nav class="flex" aria-label="Breadcrumb">
  <ol class="flex items-center gap-2 text-sm">
    <li>
      <a href="#" class="text-gray-500 hover:text-gray-700">Home</a>
    </li>
    <li class="text-gray-400">/</li>
    <li>
      <a href="#" class="text-gray-500 hover:text-gray-700">Products</a>
    </li>
    <li class="text-gray-400">/</li>
    <li>
      <span class="text-gray-900 font-medium">Widget Pro</span>
    </li>
  </ol>
</nav>

5.13 Building a Skeleton Loader

<div class="animate-pulse space-y-4">
  <div class="h-48 bg-gray-200 rounded-xl"></div>
  <div class="space-y-3">
    <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>
</div>

5.14 Building a Dropdown Menu

<div class="relative inline-block">
  <button class="px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50">
    Options
    <svg class="inline w-4 h-4 ml-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
      <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
    </svg>
  </button>

  <!-- Dropdown panel (toggle with JS) -->
  <div class="absolute right-0 z-10 mt-2 w-56 bg-white rounded-lg shadow-lg ring-1 ring-black/5">
    <div class="py-1">
      <a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">Edit</a>
      <a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">Duplicate</a>
      <a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">Archive</a>
      <div class="border-t border-gray-100 my-1"></div>
      <a href="#" class="block px-4 py-2 text-sm text-red-600 hover:bg-red-50">Delete</a>
    </div>
  </div>
</div>

5.15 Building a Tab Interface

<div>
  <div class="border-b border-gray-200">
    <nav class="flex gap-8 px-4" aria-label="Tabs">
      <a href="#" class="py-3 text-sm font-medium text-blue-600 border-b-2 border-blue-600">
        General
      </a>
      <a href="#" class="py-3 text-sm font-medium text-gray-500 hover:text-gray-700 hover:border-gray-300 border-b-2 border-transparent">
        Security
      </a>
      <a href="#" class="py-3 text-sm font-medium text-gray-500 hover:text-gray-700 hover:border-gray-300 border-b-2 border-transparent">
        Notifications
      </a>
      <a href="#" class="py-3 text-sm font-medium text-gray-500 hover:text-gray-700 hover:border-gray-300 border-b-2 border-transparent">
        Billing
      </a>
    </nav>
  </div>
  <div class="p-4">
    <!-- Tab content -->
  </div>
</div>

5.16 Building a Progress Bar

<!-- Simple progress bar -->
<div class="w-full bg-gray-200 rounded-full h-2.5">
  <div class="bg-blue-600 h-2.5 rounded-full" style="width: 65%"></div>
</div>

<!-- With label -->
<div>
  <div class="flex justify-between mb-1">
    <span class="text-sm font-medium text-gray-700">Uploading...</span>
    <span class="text-sm text-gray-500">65%</span>
  </div>
  <div class="w-full bg-gray-200 rounded-full h-2">
    <div class="bg-blue-600 h-2 rounded-full transition-all duration-300" style="width: 65%"></div>
  </div>
</div>

<!-- Segmented steps -->
<div class="flex gap-2">
  <div class="flex-1 h-2 rounded-full bg-blue-600"></div>
  <div class="flex-1 h-2 rounded-full bg-blue-600"></div>
  <div class="flex-1 h-2 rounded-full bg-blue-600"></div>
  <div class="flex-1 h-2 rounded-full bg-gray-200"></div>
  <div class="flex-1 h-2 rounded-full bg-gray-200"></div>
</div>

5.17 Building a Pagination Component

<nav class="flex items-center justify-between">
  <p class="text-sm text-gray-500">
    Showing <span class="font-medium text-gray-900">1</span> to
    <span class="font-medium text-gray-900">10</span> of
    <span class="font-medium text-gray-900">97</span> results
  </p>
  <div class="flex items-center gap-1">
    <button class="px-3 py-2 text-sm text-gray-500 hover:bg-gray-100 rounded-lg disabled:opacity-50" disabled>
      Previous
    </button>
    <button class="px-3 py-2 text-sm font-medium text-white bg-blue-600 rounded-lg">1</button>
    <button class="px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 rounded-lg">2</button>
    <button class="px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 rounded-lg">3</button>
    <span class="px-2 text-gray-400">...</span>
    <button class="px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 rounded-lg">10</button>
    <button class="px-3 py-2 text-sm text-gray-500 hover:bg-gray-100 rounded-lg">
      Next
    </button>
  </div>
</nav>

5.18 Building a Tooltip

<div class="relative group inline-block">
  <button class="px-3 py-1.5 text-sm bg-gray-900 text-white rounded-lg">
    Hover me
  </button>
  <div class="absolute bottom-full left-1/2 -translate-x-1/2 mb-2
              hidden group-hover:block
              px-3 py-1.5 text-xs text-white bg-gray-900 rounded-lg
              whitespace-nowrap shadow-lg">
    Tooltip content
    <div class="absolute top-full left-1/2 -translate-x-1/2 border-4 border-transparent border-t-gray-900"></div>
  </div>
</div>

5.19 Dark Mode Complete Pattern

<div class="bg-white dark:bg-gray-950 min-h-screen transition-colors">
  <header class="bg-white dark:bg-gray-900 border-b border-gray-200 dark:border-gray-800">
    <div class="max-w-7xl mx-auto px-4 py-4 flex items-center justify-between">
      <h1 class="text-xl font-bold text-gray-900 dark:text-white">MyApp</h1>
      <!-- Dark mode toggle button (implement with JS) -->
      <button class="p-2 rounded-lg bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-700">
        <svg class="w-5 h-5 hidden dark:block" fill="none" viewBox="0 0 24 24" stroke="currentColor">
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"/>
        </svg>
        <svg class="w-5 h-5 dark:hidden" fill="none" viewBox="0 0 24 24" stroke="currentColor">
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"/>
        </svg>
      </button>
    </div>
  </header>

  <main class="max-w-7xl mx-auto px-4 py-8">
    <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
      <div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl p-6 shadow-sm dark:shadow-gray-900/20">
        <h3 class="font-semibold text-gray-900 dark:text-gray-100">Card Title</h3>
        <p class="mt-2 text-gray-600 dark:text-gray-400 text-sm">
          Card content with proper dark mode colors.
        </p>
        <a href="#" class="mt-4 inline-block text-sm font-medium text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300">
          Learn more &rarr;
        </a>
      </div>
    </div>
  </main>
</div>

5.20 Building a Glassmorphism Card

<div class="relative">
  <!-- Colorful background -->
  <div class="absolute inset-0 bg-gradient-to-br from-purple-500 via-pink-500 to-orange-400"></div>

  <!-- Glass card -->
  <div class="relative m-16 p-8 rounded-2xl bg-white/10 backdrop-blur-lg border border-white/20 shadow-2xl">
    <h3 class="text-xl font-bold text-white">Glassmorphism</h3>
    <p class="mt-2 text-white/80">
      A frosted glass effect achieved with backdrop-blur and semi-transparent backgrounds.
    </p>
  </div>
</div>
<div class="columns-1 sm:columns-2 lg:columns-3 gap-4 space-y-4">
  <img class="w-full rounded-lg" src="photo1.jpg" alt="">
  <img class="w-full rounded-lg" src="photo2.jpg" alt="">
  <img class="w-full rounded-lg" src="photo3.jpg" alt="">
  <img class="w-full rounded-lg" src="photo4.jpg" alt="">
  <img class="w-full rounded-lg" src="photo5.jpg" alt="">
  <img class="w-full rounded-lg" src="photo6.jpg" alt="">
</div>

5.22 Aspect Ratio

<!-- Video embed -->
<div class="aspect-video rounded-lg overflow-hidden">
  <iframe class="w-full h-full" src="https://www.youtube.com/embed/..."></iframe>
</div>

<!-- Square -->
<div class="aspect-square rounded-lg overflow-hidden">
  <img class="w-full h-full object-cover" src="photo.jpg" alt="">
</div>

<!-- Custom aspect ratio -->
<div class="aspect-[4/3] rounded-lg overflow-hidden">
  <img class="w-full h-full object-cover" src="photo.jpg" alt="">
</div>

5.23 Extracting Components with @apply

When the same pattern repeats across many pages and you cannot use a framework component abstraction:

@import 'tailwindcss';

/* Button components */
.btn {
  @apply inline-flex items-center justify-center px-4 py-2 text-sm font-semibold rounded-lg transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed;
}

.btn-primary {
  @apply btn bg-blue-600 text-white hover:bg-blue-700 focus-visible:ring-blue-500;
}

.btn-secondary {
  @apply btn bg-gray-100 text-gray-700 hover:bg-gray-200 focus-visible:ring-gray-500;
}

.btn-danger {
  @apply btn bg-red-600 text-white hover:bg-red-700 focus-visible:ring-red-500;
}

.btn-ghost {
  @apply btn text-gray-600 hover:bg-gray-100 focus-visible:ring-gray-500;
}

/* Input component */
.input {
  @apply w-full px-3 py-2 border border-gray-300 rounded-lg shadow-sm text-sm placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500;
}

.input-error {
  @apply input border-red-500 focus:ring-red-500 focus:border-red-500;
}

5.24 Production Builds

Minification

All integration methods support minified output for production:

Vite: Minification happens automatically in vite build.

PostCSS: Minification is handled by your build tool (Vite, Webpack, etc.).

CLI: Use the --minify flag:

npx @tailwindcss/cli -i src/app.css -o dist/output.css --minify

What Gets Removed

Tailwind CSS only includes the CSS for utility classes it detects in your source files. If a class like bg-purple-500 appears nowhere in your scanned files, it will not be in the output. This is automatic and requires no configuration.

Safelist Patterns

If you generate class names dynamically (e.g., bg-${color}-500), Tailwind cannot detect them at build time. Use explicit class names instead:

<!-- BAD: Dynamic class construction (will NOT be detected) -->
<div class="bg-{{ color }}-500">

<!-- GOOD: Explicit full class names -->
<div class="{{ color === 'red' ? 'bg-red-500' : color === 'blue' ? 'bg-blue-500' : 'bg-gray-500' }}">

Or ensure the full class names appear somewhere in your source (even in a comment or unused variable) so the scanner detects them.

5.25 Upgrading from Tailwind CSS v3

The @tailwindcss/upgrade tool automates migration from v3 to v4.

Running the Upgrade

npx @tailwindcss/upgrade

This tool:

  • Converts tailwind.config.js to CSS-first @theme configuration
  • Updates @tailwind base/components/utilities to @import 'tailwindcss'
  • Migrates PostCSS configuration
  • Updates template files with renamed utilities
  • Converts plugin references to @plugin directives

Warning

Always commit your code before running the upgrade tool. Review all changes it makes. The tool handles most cases automatically, but complex configurations or custom plugin setups may need manual adjustment.

What the Upgrade Tool Converts

v3 Pattern v4 Equivalent
tailwind.config.js theme @theme { ... } in CSS
@tailwind base @import 'tailwindcss/preflight'
@tailwind components (removed, use @layer)
@tailwind utilities @import 'tailwindcss/utilities'
content: [...] in config @source directives in CSS
require('plugin') in config @plugin 'plugin' in CSS
theme.extend.colors @theme { --color-*: ... }

Common Manual Steps After Upgrade

  1. Review @theme output for correctness
  2. Check that @source paths cover all your template files
  3. Verify custom plugin compatibility with v4
  4. Test dark mode behavior (v4 uses prefers-color-scheme by default)
  5. Check for renamed or removed utility classes

5.26 Using Tailwind with TypeScript Projects

Tailwind works with any file that contains class strings. For TypeScript projects, ensure your @source patterns include .ts and .tsx files:

@import 'tailwindcss';

/* TypeScript files are scanned by default if in the project directory */
/* Add explicit sources if they're outside the default scan path */
@source '../src/**/*.tsx';
@source '../src/**/*.ts';

5.27 Using Tailwind with Markdown/MDX Content

For content sites that use Markdown or MDX:

@import 'tailwindcss';

@source '../content/**/*.md';
@source '../content/**/*.mdx';

The @tailwindcss/typography plugin provides beautiful default styling for rendered Markdown:

@import 'tailwindcss';
@plugin '@tailwindcss/typography';
<article class="prose lg:prose-lg dark:prose-invert max-w-none">
  <!-- Rendered Markdown content gets beautiful typography -->
</article>

5.28 Using Tailwind with CSS Modules

Tailwind works alongside CSS Modules. Use @reference to access theme tokens without duplicating output:

/* component.module.css */
@reference '../app.css';

.wrapper {
  @apply flex items-center gap-4 p-6;
}

.title {
  @apply text-xl font-bold text-gray-900;
}

5.29 Controlling Specificity with @layer

While Tailwind v4 handles specificity automatically, you can use standard CSS @layer for custom styles:

@import 'tailwindcss';

@layer base {
  h1 {
    @apply text-3xl font-bold;
  }
  h2 {
    @apply text-2xl font-semibold;
  }
}

Base layer styles have lower specificity than utility classes, so utilities always win when applied via the class attribute.

5.30 Using Custom Fonts

@import 'tailwindcss';

/* Import the font */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');

@theme {
  --font-family-sans: 'Inter', ui-sans-serif, system-ui, sans-serif;
}

Or with local font files:

@import 'tailwindcss';

@font-face {
  font-family: 'CalSans';
  src: url('/fonts/CalSans-SemiBold.woff2') format('woff2');
  font-weight: 600;
  font-display: swap;
}

@theme {
  --font-family-display: 'CalSans', sans-serif;
}

Use in HTML:

<h1 class="font-display text-4xl">Custom Display Font</h1>
<p class="font-sans text-base">Inter body text</p>

6. Troubleshooting

6.1 Build and Compilation Errors

Error: Cannot find module '../lightningcss.linux-x64-musl.node'

Cause: The native Lightning CSS binary for your platform is missing. This commonly occurs in Alpine Linux Docker containers or musl-based environments where the glibc binary was installed instead. (GitHub issue #17958)

Solution:

  1. Ensure you are running a clean install:
    rm -rf node_modules package-lock.json
    npm install
    
  2. If using Alpine Linux, ensure the musl variant is available:
    npm install lightningcss-linux-x64-musl
    
  3. If using Docker, make sure npm install runs inside the container (not on the host), so the correct platform binaries are resolved.

Prevention: Run npm install in the same OS/architecture as your build environment.


Error: Tailwind CSS is not installed

Cause: The @tailwindcss/upgrade tool cannot find a Tailwind CSS installation in the project.

Solution:

  1. Install Tailwind CSS first:
    npm install tailwindcss
    
  2. Then run the upgrade tool:
    npx @tailwindcss/upgrade
    

Error: Could not resolve '{id}' from '{base}'

Cause: An @import, @plugin, or @config directive references a module or file that cannot be found relative to the CSS file or in node_modules.

Solution:

  1. Verify the import path is correct and the file exists.
  2. For npm packages, ensure they are installed: npm install <package-name>.
  3. Check that the path is relative to the CSS file containing the directive, not your project root.

Error: The browser build does not support @import for "{id}"

Cause: You are using @import to include an external CSS file while using the @tailwindcss/browser build. The browser build compiles inline CSS only.

Solution: The browser build does not support importing external files. Either:

  • Switch to a build tool (Vite, PostCSS, CLI) for full @import support.
  • Inline all your CSS in <style type="text/tailwindcss"> tags.

Error: The browser build does not support plugins or config files.

Cause: You used @plugin or @config in a <style type="text/tailwindcss"> block with the browser build.

Solution: The browser build is intentionally limited. Switch to a Node.js-based build tool (Vite plugin, PostCSS, or CLI) if you need plugins or config files.


Error: The source(...) does not exist or is not a directory.

Cause: The source(...) function references a path that does not exist on disk.

Solution:

  1. Verify the path exists: ls -la ../src (or whatever path you specified).
  2. Ensure the path is a directory, not a file.
  3. Use a path relative to the CSS file location.

6.2 @apply Errors

Error: You cannot use @apply inside @keyframes.

Cause: Tailwind does not support @apply within @keyframes blocks because keyframe declarations have different semantics than regular CSS rules.

Solution: Write raw CSS properties inside @keyframes:

/* BAD */
@keyframes fade-in {
  from { @apply opacity-0; }
  to { @apply opacity-100; }
}

/* GOOD */
@keyframes fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

Error: Cannot apply unknown utility class '{candidate}'

Cause: The class name referenced in @apply does not correspond to any known Tailwind utility or custom utility defined with @utility.

Solution:

  1. Check for typos in the class name.
  2. Verify the utility exists in the current Tailwind version (some v3 utilities were renamed or removed in v4).
  3. If it is a custom utility, ensure it is defined with @utility before the @apply usage.

Error: Cannot apply unprefixed utility class '{candidate}'. Did you mean '{prefix}:{candidate}'?

Cause: Your project uses a class prefix, and you used the unprefixed form in @apply.

Solution: Include the prefix:

/* If your prefix is 'tw' */
.my-class {
  @apply tw:px-4 tw:py-2 tw:bg-blue-500;
}

Error: Cannot apply utility class '{candidate}' because it creates a circular dependency.

Cause: A class defined with @apply references another class that eventually references the original class, creating an infinite loop.

Solution: Break the circular chain by inlining the CSS properties directly for one of the classes:

/* BAD: Circular */
.foo { @apply bar; }
.bar { @apply foo; }

/* GOOD: Break the cycle */
.foo { @apply bar; }
.bar { padding: 1rem; color: blue; }

6.3 Theme Function Errors

Error: The --theme(...) function can only be used with CSS variables from your theme.

Cause: You passed a CSS variable to --theme() that is not defined in any @theme block.

Solution:

  1. Ensure the variable is defined in @theme:
    @theme {
      --color-brand: #3b82f6;
    }
    
  2. Use var() instead if referencing non-theme custom properties:
    .element {
      /* For theme variables */
      color: --theme(--color-brand);
      /* For non-theme custom properties */
      color: var(--my-custom-color);
    }
    

Error: The --spacing(...) function requires an argument, but received none.

Cause: --spacing() was called with empty parentheses.

Solution: Provide a spacing scale value:

.element {
  padding: --spacing(4);
  margin: --spacing(2);
}

6.4 Scanner and Source Detection Issues

Classes not being generated (scanner misses)

Cause: The Oxide scanner could not find your class candidates. Common reasons:

  1. Files are outside the scan path.
  2. Files are in .gitignore.
  3. Class names are dynamically constructed.
  4. File type is not recognized by the scanner.

Solution:

  1. Add explicit @source directives:
    @source '../path/to/templates/**/*.html';
    
  2. For dynamically constructed classes, use complete class names:
    <!-- BAD: Scanner can't detect this -->
    <div class="text-{{ color }}-500">
    
    <!-- GOOD: Full class names the scanner can detect -->
    <div class="{{ color === 'red' ? 'text-red-500' : 'text-blue-500' }}">
    

Oxide scanner fails on arbitrary value classes (GitHub issue #19863)

Cause: In v4.2.2, certain arbitrary value patterns like max-h-[85vh] may not be detected by the Oxide scanner in some contexts.

Solution:

  1. Verify the class name syntax is correct.
  2. Try writing the value as a custom utility if the arbitrary value is not detected:
    @utility max-h-85vh {
      max-height: 85vh;
    }
    
  3. Check the GitHub issue for updates and patches.

@source silently ignores paths excluded by .gitignore (GitHub issue #19844)

Cause: The Oxide scanner respects .gitignore rules even for explicitly declared @source paths. If a directory appears in an allow-list .gitignore (a .gitignore that ignores everything except specific patterns), the @source directive may silently skip matching files.

Solution:

  1. Check your .gitignore for patterns that might exclude the targeted files.
  2. If the files must remain gitignored, consider copying them to a non-ignored location during build.
  3. As a workaround, restructure your .gitignore so the source files are not excluded.

Source glob does not match Next.js catchall routes like [...slug] (GitHub issue #16287)

Cause: The bracket characters in Next.js dynamic route segments (e.g., pages/[...slug].tsx) can interfere with glob pattern matching.

Solution:

  1. Use a broader glob pattern that does not require matching the brackets:
    @source '../pages/**/*.tsx';
    @source '../app/**/*.tsx';
    
  2. Avoid overly specific glob patterns that try to match bracket characters.

6.5 Platform and Environment Issues

Error: Unsupported OS: openbsd (GitHub issue #17452)

Cause: Tailwind CSS v4's native Oxide addon does not ship prebuilt binaries for OpenBSD.

Solution:

  1. Use the standalone CLI binary if a compatible build exists for your platform.
  2. Use a Docker container with a supported Linux distribution for building.
  3. Cross-compile the CSS on a supported platform and copy the output.

Can't build on Linux ARM (missing @tailwindcss/oxide-linux-arm64-gnu) (GitHub issue #15806)

Cause: The native Oxide binary for Linux ARM64 may not be included in some installation scenarios.

Solution:

  1. Ensure you install with a clean node_modules:
    rm -rf node_modules
    npm install
    
  2. Explicitly install the ARM64 binary:
    npm install @tailwindcss/oxide-linux-arm64-gnu
    
  3. If building in CI, ensure the CI runner architecture matches your deployment target.

Invalid code point error on Windows with backslash + hex UUID in path (GitHub issue #19910)

Cause: On Windows, file paths containing backslashes followed by hexadecimal characters can be misinterpreted as Unicode escape sequences, causing invalid code point errors.

Solution:

  1. Avoid file paths that combine backslashes with hex-like characters.
  2. Move your project to a path without special characters.
  3. Use forward slashes in path configurations where possible.

CLI no longer works with Docker bind mounts (GitHub issue #18540)

Cause: The file watching mechanism in the Oxide scanner may not properly detect changes through Docker bind mount boundaries.

Solution:

  1. Use polling mode if available.
  2. Run the Tailwind build process inside the Docker container rather than on the host.
  3. Consider using volume mounts instead of bind mounts.

6.6 Vite Integration Issues

@tailwindcss/vite emits SOURCEMAP_BROKEN warnings in Nuxt/Vite (GitHub issue #19930)

Cause: The Vite plugin may emit source map warnings when used with Nuxt or certain Vite configurations.

Solution:

  1. These warnings are cosmetic and do not affect the generated CSS.
  2. Check the GitHub issue for a patch or workaround specific to your Nuxt version.
  3. Suppressing source map warnings in Vite config may help:
    // vite.config.js
    export default defineConfig({
      css: {
        devSourcemap: false,
      },
    })
    

HMR not working with Vite 7 + SolidStart v2 (GitHub issue #19818)

Cause: Compatibility issue between the Tailwind Vite plugin and Vite 7 / SolidStart v2's HMR implementation.

Solution:

  1. Check the GitHub issue for updates.
  2. As a workaround, use the PostCSS plugin instead of the Vite plugin.
  3. Manually refresh the browser during development until a fix is released.

@tailwindcss/vite forces full reload for Angular component stylesheets (GitHub issue #19903)

Cause: When editing Angular component CSS files, the Vite plugin may trigger a full page reload instead of a hot update.

Solution:

  1. This is a known issue with the interaction between Angular's component stylesheet pipeline and the Tailwind Vite plugin.
  2. Consider using the PostCSS integration for Angular projects instead.

DeprecationWarning: module.register() deprecated (GitHub issue #19893)

Cause: Node.js deprecation warning for module.register() used internally by the Tailwind Vite plugin or related tooling.

Solution:

  1. This is a Node.js-level deprecation warning, not a Tailwind bug. It is informational and does not affect functionality.
  2. Upgrading to the latest Tailwind CSS and Vite versions may resolve it.

6.7 Watch Mode Issues

Watch mode not refreshing files in assets folder (GitHub issue #17632)

Cause: The file watcher may not detect changes in certain directories, especially those outside the default scan path.

Solution:

  1. Add an explicit @source directive for the assets directory:
    @source '../assets/**/*.html';
    
  2. Ensure the directory is not excluded by .gitignore.
  3. Restart the watch process after adding new directories.

6.8 General Troubleshooting Steps

Classes appear in source but are not styled

  1. Check the CSS import: Ensure @import 'tailwindcss' is present in your CSS entry file.
  2. Check source scanning: Add @source directives if your templates are outside the project root.
  3. Check .gitignore: Scanned paths must not be gitignored.
  4. Check for typos: Tailwind class names are case-sensitive (bg-Blue-500 will not work, use bg-blue-500).
  5. Check build output: Inspect the compiled CSS to see if the class is present.

CSS file is very large in development

This is expected. In development, Tailwind may include more CSS for faster HMR. Production builds automatically tree-shake unused classes.

Styles appear but are overridden

  1. Check CSS source order. Styles loaded later win.
  2. Check specificity. Tailwind utilities are single-class selectors. If your custom CSS uses more specific selectors (IDs, nested selectors), they will override utilities.
  3. Use !important modifier if absolutely necessary: !bg-blue-500 (prefix with !).

IntelliSense / autocomplete not working

  1. Install the Tailwind CSS IntelliSense VS Code extension.
  2. Ensure your CSS file has @import 'tailwindcss' (the extension needs this to activate).
  3. Restart VS Code after installing Tailwind CSS packages.

Preflight (CSS reset) is unwanted

Import only the layers you need:

/* Skip Preflight entirely */
@import 'tailwindcss/theme';
@import 'tailwindcss/utilities';

Colors look different from v3

Tailwind v4 uses the OKLCH color space by default, which provides perceptually uniform colors. The hex values may differ from v3's sRGB-based palette. If you need exact v3 colors, define them explicitly in @theme.


7. FAQ

Q: What version of Node.js do I need?

Tailwind CSS v4 requires Node.js 20 or later. This is enforced in the package.json engines field. Earlier Node versions will fail at install or build time.


Q: Do I still need a tailwind.config.js file?

No. Tailwind CSS v4 uses CSS-first configuration with directives like @theme, @source, and @plugin directly in your CSS. The @config directive exists as a backward-compatibility bridge for v3 config files during migration, but new projects should use CSS-first configuration exclusively.


Q: How do I migrate from Tailwind CSS v3 to v4?

Run npx @tailwindcss/upgrade in your project. It automatically converts your tailwind.config.js to CSS @theme blocks, updates @tailwind directives to @import, and migrates PostCSS configuration. Always commit before running and review the changes.


Q: Can I use Tailwind without Node.js?

Yes. The @tailwindcss/standalone binary is a self-contained executable built with Bun. It includes the Tailwind compiler and several first-party plugins (@tailwindcss/forms, @tailwindcss/typography, @tailwindcss/aspect-ratio). Download it and run it directly.


Q: Which build tool integration should I choose?

  • Vite projects: Use @tailwindcss/vite (fastest HMR, recommended).
  • Webpack projects: Use @tailwindcss/webpack.
  • Any PostCSS setup (Next.js, Nuxt, Angular): Use @tailwindcss/postcss.
  • No build tool: Use @tailwindcss/cli.
  • No Node.js: Use @tailwindcss/standalone.
  • Prototyping: Use @tailwindcss/browser (CDN, not for production).

Q: How does Tailwind know which classes I'm using?

The Oxide engine (written in Rust) scans your source files for strings that look like utility class names. It does not execute your code or parse templates semantically -- it performs string extraction. Any string matching a valid utility pattern in a scanned file will generate the corresponding CSS.


Q: What file types does the scanner detect classes in?

Beyond standard HTML, JS, and TS files, the Oxide scanner handles: Clojure, Elixir (.heex, .leex), Haml, JSON, Markdown, Pug, Razor (.cshtml, .razor), Ruby (.rb, .erb), Rust, Slim, Svelte, and Vue files. Custom file types can be included via @source glob patterns.


Q: Why are my dynamically constructed class names not working?

Tailwind's scanner looks for complete class name strings. It cannot resolve dynamic concatenation like bg-${color}-500. Use complete, literal class names in conditional expressions or map objects:

const colorClasses = {
  red: 'bg-red-500 text-red-50',
  blue: 'bg-blue-500 text-blue-50',
  green: 'bg-green-500 text-green-50',
}

Q: How do I add custom colors?

Define them in a @theme block:

@theme {
  --color-brand: #3b82f6;
  --color-brand-light: #93c5fd;
  --color-brand-dark: #1d4ed8;
}

This generates text-brand, bg-brand, border-brand, ring-brand, etc.


Q: How do I add custom breakpoints?

Define them in a @theme block:

@theme {
  --breakpoint-xs: 30rem;
  --breakpoint-3xl: 120rem;
}

Then use them as responsive variants: xs:flex, 3xl:grid-cols-4.


Q: How do I completely replace the default theme?

Use --*: initial in a @theme block to reset all defaults, then define your complete design system:

@theme {
  --*: initial;
  --color-primary: #000;
  --color-secondary: #666;
  --spacing-1: 0.25rem;
  --spacing-2: 0.5rem;
  /* ... define everything you need */
}

Q: Can I use Tailwind with CSS Modules?

Yes. Use the @reference directive in your CSS Module file to access theme tokens and utilities via @apply without duplicating CSS output:

/* component.module.css */
@reference '../app.css';

.wrapper {
  @apply flex items-center gap-4;
}

Q: How do I use Tailwind with a CSS preprocessor (Sass, Less)?

Tailwind v4 does not require a preprocessor. The @theme, @utility, @variant, and nesting features cover most preprocessor use cases. If you must use a preprocessor alongside Tailwind, run the preprocessor first and pipe its output to Tailwind via PostCSS.


Q: What is Preflight and can I disable it?

Preflight is Tailwind's CSS reset (based on modern-normalize). It provides consistent cross-browser defaults. To disable it, import only the layers you need:

@import 'tailwindcss/theme';
@import 'tailwindcss/utilities';

Q: How do I use dark mode?

Add dark: variant to any utility: dark:bg-gray-900, dark:text-white. By default, dark mode follows the operating system preference via prefers-color-scheme. See the Admin Guide for details on implementing class-based dark mode toggling.


Q: How do I make a utility !important?

Prefix the utility with !:

<div class="!bg-blue-500">Always blue, regardless of specificity conflicts</div>

Q: Can I use @apply inside @keyframes?

No. The error You cannot use @apply inside @keyframes. is intentional. Write raw CSS properties inside keyframes:

@keyframes fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

Q: How do I reference theme values in custom CSS?

Use the --theme() function or standard var() with theme custom properties:

.custom {
  color: --theme(--color-brand);
  padding: --spacing(4);
  /* Or using var() */
  color: var(--color-brand);
}

Q: How do I use container queries?

Wrap the parent in @container and use @sm:, @md:, @lg: etc. on children:

<div class="@container">
  <div class="@md:flex @md:gap-4">
    Responsive to container width
  </div>
</div>

Q: Why is my output CSS file very large?

In development, Tailwind may include extra CSS for faster HMR. In production builds, only the CSS for detected utility classes is included. Check:

  1. That you are running a production build (not a dev build).
  2. That your @source patterns are not too broad (scanning unnecessary files).
  3. That you do not have many unused custom @theme tokens.

Q: How do I use Tailwind with server-side rendered (SSR) frameworks?

Tailwind works with any SSR framework (Next.js, Nuxt, SvelteKit, Remix, Astro, etc.) through the PostCSS or Vite plugin. The CSS is generated at build time, not at runtime. No special SSR configuration is needed.


Q: What is the @reference directive for?

@reference imports another CSS file's theme tokens and utility definitions for use with @apply and IntelliSense, without including that file's generated CSS in the output. It is useful for component-level CSS files that need access to the global theme.


Q: How do I handle right-to-left (RTL) layouts?

Use logical property utilities (ps-*, pe-*, ms-*, me-*) which map to padding-inline-start, padding-inline-end, etc. These automatically flip in RTL contexts. You can also use rtl: and ltr: variants for direction-specific styles.


Q: How does the source(none) option work?

Adding source(none) to your Tailwind import disables automatic source detection. You must then explicitly list every path:

@import 'tailwindcss' source(none);
@source '../app/**/*.tsx';
@source '../components/**/*.tsx';

This gives you exact control over what is scanned.


Q: Can I use Tailwind with Web Components / Shadow DOM?

Yes, but Tailwind's styles need to be available inside the Shadow DOM. You can either adopt the stylesheet programmatically or include Tailwind's output inside each component's shadow root. See the Admin Guide for implementation patterns.


Q: What is the difference between @import 'tailwindcss' and importing individual layers?

@import 'tailwindcss' is a shorthand that includes Preflight + Theme + Utilities. The granular imports (tailwindcss/preflight, tailwindcss/theme, tailwindcss/utilities) let you selectively include layers or insert custom CSS between them.


Q: How do I use the canonicalize CLI command?

The canonicalize command normalizes your Tailwind CSS file, reordering directives and formatting consistently:

npx @tailwindcss/cli canonicalize -i src/app.css -o src/app.css

This is useful for maintaining consistent CSS file formatting across a team.


Q: Can I use multiple @theme blocks?

Yes. Multiple @theme blocks merge together. This is useful for organizing tokens across multiple CSS files or logical groupings:

@theme { --color-brand: blue; }
@theme { --font-family-display: 'Cal Sans'; }

Both tokens are available.


Q: How do I use the opacity modifier syntax?

Append /{percentage} to any color utility:

<div class="bg-black/50">50% opacity black</div>
<div class="text-blue-600/75">75% opacity blue text</div>
<div class="border-gray-900/10">10% opacity border</div>

The number is a percentage from 0 to 100.


Q: My Tailwind IntelliSense shows v3 completions. How do I fix it?

Ensure the Tailwind CSS IntelliSense VS Code extension is up to date and that your project has Tailwind CSS v4 installed (not v3). The extension detects the installed version automatically. Restart VS Code after upgrading.