Skip to content

Tailwind CSS Hoja de referencia

Utility-first CSS framework for rapid UI development.

01

Getting Started

Installation via CDN

The CDN script is the fastest way to prototype with Tailwind. It generates utilities at runtime by scanning your markup. For production, prefer the PostCSS or CLI build to purge unused classes and ship a tiny CSS bundle.

tailwind
<!-- Quick start: drop this in <head> -->
<script src="https://cdn.tailwindcss.com"></script>

<!-- Tailwind scans class names in your HTML and generates styles on the fly -->
<h1 class="text-3xl font-bold text-blue-600">Hello Tailwind</h1>

Project Setup (CLI)

The content array is critical — Tailwind only generates classes it finds in those files (tree-shaking). Forgetting a path is the #1 cause of 'my class is missing' bugs. Use --watch during development.

tailwind
# Install Tailwind as a project dependency
npm install -D tailwindcss
npx tailwindcss init

# tailwind.config.js — tell Tailwind where your templates live
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ["./src/**/*.{html,js,jsx,ts,tsx}"],
  theme: { extend: {} },
  plugins: [],
};

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

Input CSS Directives

The @tailwind directives inject Tailwind's three layers in order: base (resets), components, utilities. @layer lets you add your own CSS into the right cascade layer. @apply inlines utility styles into a custom rule.

tailwind
/* src/input.css — the three layers Tailwind uses */
@tailwind base;      /* normalize/reset + base element styles */
@tailwind components; /* component classes you register */
@tailwind utilities;  /* the utility classes themselves */

/* Add custom CSS after the directives */
@layer base {
  h1 { @apply text-2xl; }
}

Utility-First Mental Model

Tailwind's philosophy: build UIs by composing small single-purpose utility classes rather than inventing semantic class names. This keeps CSS flat, avoids dead code, and makes designs consistent through a shared spacing/color scale.

tailwind
<!-- Instead of naming custom classes, compose utilities -->
<button class="bg-blue-600 hover:bg-blue-700 text-white
               font-medium py-2 px-4 rounded-lg shadow
               transition-colors duration-200">
  Save
</button>

<!-- Equivalent to writing CSS: .btn { background, padding, radius... } -->
<!-- But each utility maps to a single, predictable declaration. -->

Config & Theme Extension

Use theme.extend to add to Tailwind's defaults without replacing them. Defining a key at the top level of theme (not extend) replaces that scale entirely. Custom colors like brand-500 generate bg-brand-500, text-brand-500, border-brand-500, etc.

tailwind
// tailwind.config.js
module.exports = {
  content: ["./src/**/*.{html,tsx}"],
  theme: {
    extend: {
      colors: {
        brand: { 500: "#06B6D4", 600: "#0891B2" },
      },
      fontFamily: {
        sans: ["Inter", "system-ui", "sans-serif"],
      },
      spacing: { 128: "32rem" },
    },
  },
  plugins: [],
};
02

Colors

Text, Background & Border Colors

Color utilities follow the pattern {property}-{color}-{shade}. Shades run 50 (lightest) to 950 (darkest). Common properties: text-, bg-, border-, ring-, fill-, stroke-, from-/to-/via- (gradients).

tailwind
<p class="text-red-500">Red text</p>
<div class="bg-blue-100">Light blue background</div>
<span class="border border-gray-300">Gray border</span>
<button class="bg-emerald-500 hover:bg-emerald-600">Emerald</button>

Opacity Modifiers

Append /{opacity} to any color utility to set its alpha channel. This uses color-mix or rgba under the hood and works for text, bg, border, ring, etc. It's the cleanest way to tint without defining new palette entries.

tailwind
<div class="bg-black/50">50% black overlay</div>
<p class="text-blue-600/75">75% opacity blue text</p>
<div class="border-gray-900/10">10% gray border</div>
<button class="bg-indigo-500 hover:bg-indigo-500/90">Slight fade</button>

Gradients

Use bg-gradient-to-{direction} with from-, via-, and to- color stops. Directions include t (top), b, l, r, tr, tl, br, bl. For radial/conic gradients (v3.3+) use bg-gradient-radial (requires plugin or arbitrary value).

tailwind
<div class="bg-gradient-to-r from-purple-500 to-pink-500">
  Left to right gradient
</div>

<div class="bg-gradient-to-tr from-yellow-400 via-red-500 to-pink-600">
  Three-stop diagonal gradient
</div>

<div class="bg-gradient-to-b from-sky-400 to-sky-900">Vertical</div>

Custom & Arbitrary Colors

Arbitrary values in square brackets let you use any CSS color without editing config — great for one-offs. For colors used repeatedly, define them in theme.extend.colors so they get opacity-modifier support and consistent naming.

tailwind
<!-- Arbitrary hex/rgb value -->
<div class="bg-[#1da1f2]">Twitter blue</div>
<p class="text-[rgb(255,0,0)]">Red</p>

<!-- Custom color from your theme -->
<button class="bg-brand-600">My brand color</button>

<!-- Current color / transparent -->
<div class="bg-transparent border border-current">Transparent</div>

Color Palette Overview

Tailwind's palette replaces generic 'gray' with four neutral families: slate (cool blue), gray, zinc, neutral, and stone (warm). Pick one for your whole project for consistent neutrals. Each color has 11 shades (50, 100, ..., 950).

tailwind
<!-- Tailwind ships 22 color families, each 50-950 -->
<!-- slate gray zinc neutral stone red orange amber yellow -->
<!-- lime green emerald teal cyan sky blue indigo violet -->
<!-- purple fuchsia pink rose -->

<p class="text-slate-900">Primary text</p>
<p class="text-slate-500">Secondary text</p>
<p class="text-slate-400">Muted text</p>

<!-- Use slate/zinc/neutral/stone instead of plain gray -->
<!-- They have subtler blue/warm tones than old gray-*. -->
03

Typography

Font Size & Weight

text-{size} maps to a rem-based scale (text-base = 1rem). font-{weight} covers 100-900. Arbitrary values like text-[42px] work too. Line height auto-scales with text size unless you override with leading-*.

tailwind
<p class="text-xs">12px</p>
<p class="text-sm">14px</p>
<p class="text-base">16px (default)</p>
<p class="text-lg">18px</p>
<p class="text-2xl">24px</p>
<p class="text-7xl">72px</p>

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

Line Height & Letter Spacing

leading-* sets line-height (numeric = rem, named = relative). tracking-* sets letter-spacing. Pair uppercase + tracking-wider + text-xs for small-caps-style labels and eyebrows — a very common Tailwind idiom.

tailwind
<p class="leading-none">Line height 1</p>
<p class="leading-tight">1.25</p>
<p class="leading-normal">1.5 (default)</p>
<p class="leading-loose">2</p>
<p class="leading-6">1.5rem fixed</p>

<p class="tracking-tight">-0.025em</p>
<p class="tracking-normal">0</p>
<p class="tracking-wide">0.025em</p>
<p class="tracking-widest">0.1em</p>

<!-- Uppercase + tracking for labels -->
<span class="uppercase tracking-wider text-xs font-bold">Label</span>

Text Alignment & Decoration

text-{left,center,right,justify} aligns inline content. underline/line-through/no-underline toggle text-decoration; decoration-{1-4} sets thickness, underline-offset-{n} positions it. The hover:underline pattern is the standard for nav links.

tailwind
<p class="text-left">Left</p>
<p class="text-center">Center</p>
<p class="text-right">Right</p>
<p class="text-justify">Justified long paragraph...</p>

<a class="underline">Underlined</a>
<a class="line-through">Strikethrough</a>
<a class="no-underline hover:underline">Hover underline</a>

<a class="decoration-2 underline-offset-4">Thicker underline, offset</a>

Font Family & Arbitrary Fonts

Three font stacks ship by default: sans (system UI), serif, mono. Add more in theme.extend.fontFamily (e.g. display, body). For arbitrary one-off fonts use font-['Name']. Remember to @import or <link> the actual web font in your CSS/HTML.

tailwind
<p class="font-sans">Default sans-serif stack</p>
<p class="font-serif">Serif stack</p>
<p class="font-mono">Monospace</p>

<!-- Arbitrary font family -->
<p class="font-['Georgia']">Georgia</p>

<!-- After configuring theme.extend.fontFamily -->
<p class="font-display">Custom display font</p>

Text Overflow & Truncation

truncate = overflow-hidden text-ellipsis whitespace-nowrap (one line + ellipsis). line-clamp-{1-6} clamps to N lines (uses -webkit-line-clamp). For free-flowing wrapping use break-words or break-all to control long-word breaking.

tailwind
<!-- Single-line ellipsis -->
<p class="truncate w-64">
  Very long text that will be cut off with an ellipsis at the end...
</p>

<!-- Clip without ellipsis -->
<p class="overflow-clip w-32">Long text clipped</p>

<!-- Multi-line clamp (2 lines) -->
<p class="line-clamp-2">
  Multi-line paragraph that gets clamped after two lines
  with an ellipsis, useful for card previews and previews.
</p>
04

Spacing

Padding & Margin

Spacing utilities use a single 4px-based scale: 1 = 0.25rem = 4px. p* / m* for all sides, px/py for axis pairs, pt/pr/pb/pl or mt/mr/mb/ml per side. mx-auto centers block-level elements horizontally.

tailwind
<!-- p-* = padding, m-* = margin -->
<div class="p-4">16px all sides</div>
<div class="px-4 py-2">16px horizontal, 8px vertical</div>
<div class="pt-2 pr-4 pb-2 pl-4">Per side (top/right/bottom/left)</div>

<div class="m-8">32px margin all sides</div>
<div class="mx-auto">Center a block (auto L/R margin)</div>
<div class="mt-0 mb-4">No top margin, 16px bottom</div>

The Spacing Scale

One scale governs padding, margin, gap, width, height, and more — this consistency is Tailwind's superpower. Use negative values (-mt-2) for overlaps and offset pulls. Arbitrary values p-[13px] escape the scale when needed but should be rare.

tailwind
<!-- The default scale (in px) -->
0 = 0px      1 = 4px     2 = 8px     3 = 12px    4 = 16px
5 = 20px     6 = 24px    8 = 32px    10 = 40px   12 = 48px
16 = 64px    20 = 80px   24 = 96px   32 = 128px  48 = 192px

<!-- Negative margins -->
<div class="-mt-4">Pulls up by 16px</div>
<div class="-ml-2">Pulls left by 8px</div>

<!-- Arbitrary values -->
<div class="p-[13px] mt-[7px]">Custom sizes</div>

Space Between Children

space-x-* / space-y-* add margin between siblings (not around) — perfect for vertical stacks and rows of badges. Note: space-x uses margin-left, so it doesn't combine well with flex justify; for flex prefer the gap-* utility (see Flexbox).

tailwind
<div class="space-y-4">
  <div>Item 1</div>
  <div>Item 2</div>
  <div>Item 3</div>
</div>
<!-- Adds 16px margin-top to every child except the first -->

<div class="space-x-2 flex">
  <span>A</span><span>B</span><span>C</span>
</div>
<!-- Adds 8px margin-left to every child except the first -->

Width & Height

w-* / h-* use the spacing scale plus fractions (1/2, 1/3, 2/3, 1/4...), screen/ full, and named sizes (xs..7xl for max-width). max-w-{size} caps width — wrap page content in max-w-md mx-auto for readable line lengths. w-fit / w-max use intrinsic sizing.

tailwind
<div class="w-16 h-16">64x64 box</div>
<div class="w-1/2 h-full">50% width, full height</div>
<div class="w-screen h-screen">Full viewport</div>
<div class="w-96">24rem fixed</div>
<div class="max-w-md mx-auto">Capped width, centered</div>
<div class="min-h-screen">At least full viewport tall</div>

<!-- Modern: fit-content, intrinsic sizing -->
<div class="w-fit">Shrinks to content</div>

Gap for Flex & Grid

gap-* is the modern way to space flex/grid children — replaces the older space-x/space-y margin approach. Set gap for both axes, or gap-x/gap-y individually. Uses the same spacing scale as padding/margin.

tailwind
<div class="flex gap-4">
  <div>A</div><div>B</div><div>C</div>
</div>
<!-- 16px between flex children, no margin hacks needed -->

<div class="grid grid-cols-3 gap-2 gap-y-4">
  <div>1</div><div>2</div><div>3</div>
  <div>4</div><div>5</div><div>6</div>
</div>
<!-- gap = both axes; gap-x / gap-y for per-axis -->
05

Flexbox

Basic Flex Container

flex sets display:flex; inline-flex sets display:inline-flex. flex-col switches the main axis to vertical — combined with gap it's the cleanest way to build vertical stacks. Default direction is row (horizontal).

tailwind
<div class="flex">
  <div>A</div><div>B</div><div>C</div>
</div>

<div class="inline-flex gap-2">
  <span>Badge</span><span>Badge</span>
</div>

<!-- Vertical stack = flex-col (often cleaner than space-y) -->
<div class="flex flex-col gap-4">
  <div>Row 1</div>
  <div>Row 2</div>
</div>

Justify & Align

justify-* controls the main axis (horizontal in flex-row); items-* controls the cross axis (vertical in flex-row). The combo 'flex justify-center items-center' centers content both ways — the most-used Tailwind snippet for centering.

tailwind
<div class="flex justify-start">   <!-- left   --></div>
<div class="flex justify-center">  <!-- center --></div>
<div class="flex justify-between"> <!-- spread --></div>
<div class="flex justify-around">  <!-- equal space around --></div>
<div class="flex justify-end">     <!-- right  --></div>

<!-- Cross axis (perpendicular to main) -->
<div class="flex items-center">     <!-- vertically center --></div>
<div class="flex items-start">      <!-- top align --></div>
<div class="flex items-end">        <!-- bottom align --></div>
<div class="flex items-stretch">    <!-- fill height --></div>

Flex Grow, Shrink & Basis

flex-1 = flex:1 1 0% (grow to fill, can shrink, basis 0). flex-none = don't grow or shrink (fixed). flex-grow-0 / flex-shrink-0 disable growth/shrink individually. basis-{n} sets the initial size before growing.

tailwind
<div class="flex">
  <div class="flex-1">Grows to fill</div>
  <div class="flex-none">Never shrinks (fixed)</div>
  <div class="flex-initial">Default size, can shrink</div>
</div>

<div class="flex">
  <div class="flex-grow-0 w-20">Fixed 80px</div>
  <div class="flex-grow basis-0">Takes remaining</div>
</div>

<!-- Responsive: sidebar collapses on mobile -->
<div class="flex flex-col md:flex-row">
  <aside class="md:w-64 md:flex-shrink-0">Sidebar</aside>
  <main class="flex-1">Main</main>
</div>

Flex Wrap & Order

flex-wrap lets children flow to new lines (default nowrap overflows). order-{n} reorders children visually without changing DOM — order-first/last are shortcuts. Useful for responsive layouts where you want different visual order per breakpoint.

tailwind
<div class="flex flex-wrap gap-4">
  <div class="w-40">Card</div>
  <div class="w-40">Card</div>
  <div class="w-40">Card</div>
  <!-- Cards wrap to next line instead of overflowing -->
</div>

<div class="flex flex-wrap-reverse">Wrap backwards</div>
<div class="flex flex-nowrap">No wrapping (default)</div>

<!-- Reorder children -->
<div class="flex">
  <div class="order-last">First in DOM, last visually</div>
  <div class="order-first">Last in DOM, first visually</div>
  <div class="order-2">Custom order</div>
</div>

Centering Patterns

flex items-center justify-center is the canonical centering snippet — works for any content size. The sticky-footer pattern (min-h-screen + flex-col + flex-1 main) pushes the footer to the bottom even with little content.

tailwind
<!-- Center anything both axes (classic) -->
<div class="flex items-center justify-center h-screen">
  <div>Dead center</div>
</div>

<!-- Sticky footer pattern -->
<div class="flex flex-col min-h-screen">
  <header>Header</header>
  <main class="flex-1">Content grows</main>
  <footer>Footer</footer>
</div>

<!-- Space between with centered item -->
<div class="flex items-center justify-between">
  <button>Left</button>
  <h1 class="absolute left-1/2 -translate-x-1/2">Centered title</h1>
  <button>Right</button>
</div>
06

Grid

Basic Grid

grid sets display:grid. grid-cols-{n} defines a fixed column count (1-12). auto-rows-fr makes every row equal height (1fr each). gap-* works just like in flex for spacing tracks.

tailwind
<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>

<!-- Auto rows set the row height -->
<div class="grid grid-cols-2 auto-rows-fr gap-2">
  <div>Equal-height rows</div>
  <div>Equal-height rows</div>
</div>

<!-- Inline grid -->
<span class="inline-grid grid-cols-2 gap-1">...</span>

Responsive Columns

The auto-fit + minmax pattern is a powerful responsive trick: columns are at least 200px and stretch to fill the row, wrapping automatically — no media queries needed. Combine with explicit responsive grid-cols-* for more control.

tailwind
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
  <!-- 1 column on mobile, 2 on small, 3 on large, 4 on xl -->
</div>

<!-- Auto-fit / minmax for card grids that wrap naturally -->
<div class="grid grid-cols-[repeat(auto-fit,minmax(200px,1fr))] gap-4">
  <div>Card</div><div>Card</div><div>Card</div>
</div>

Column & Row Spans

col-span-{n} / row-span-{n} make an item cover multiple tracks. col-start-{n} / col-end-{n} place items at explicit grid lines. Together these enable complex magazine-style layouts without media queries.

tailwind
<div class="grid grid-cols-3 grid-rows-3 gap-2">
  <div class="col-span-2">Spans 2 cols</div>
  <div>1 col</div>
  <div class="row-span-2">Spans 2 rows</div>
  <div class="col-span-2 row-span-2">Big tile</div>
  <div>1 col</div>
  <div>1 col</div>
</div>

<!-- Explicit placement -->
<div class="col-start-2 col-end-4 row-start-1">
  Placed at column 2-4, row 1
</div>

Grid Template Areas via Arbitrary Values

Arbitrary values in square brackets let you specify any grid-template syntax: grid-cols-[200px_1fr_100px] creates three custom-width tracks (underscores become spaces). Named grid-template-areas isn't a built-in utility — define it in a custom class or use the layout via col/row spans.

tailwind
<div class="grid grid-cols-[200px_1fr] grid-rows-[auto_1fr_auto] gap-4
            min-h-screen">
  <aside class="row-span-3">Sidebar</aside>
  <header>Header</header>
  <main>Main</main>
  <footer>Footer</footer>
</div>

<!-- Named template areas need custom CSS or plugin: -->
<style>
  .app { grid-template-areas: "h h" "s m" "f f"; }
</style>

Gap & Alignment

justify-items-* / content-* control how items sit within their cells and how the tracks sit within the container. place-items-center is shorthand for justify-items + items-content (both axes). place-content-center centers the entire grid block.

tailwind
<div class="grid grid-cols-3 gap-4 gap-x-8 gap-y-2">
  <!-- 32px col gap, 8px row gap -->
</div>

<!-- Align whole grid tracks -->
<div class="grid grid-cols-2 justify-items-center">
  <div>Each item centered in its cell</div>
</div>

<div class="grid grid-cols-2 content-center h-64">
  <div>Vertically centers the rows</div>
</div>

<div class="grid grid-cols-2 place-items-center">
  <!-- Both axes at once -->
</div>
07

Borders

Border Width & Color

border sets 1px on all sides; border-{2,4,8} set thickness. border-{t,r,b,l,x,y} target specific sides. border-dashed/dotted/double set the style. Always pair with border-{color} — Tailwind's default border color is gray-200 (changed from gray-300 in v3).

tailwind
<div class="border">1px all sides</div>
<div class="border-2">2px</div>
<div class="border-4 border-red-500">4px red</div>

<div class="border-t border-b">Only top & bottom</div>
<div class="border-l-4 border-emerald-500">Left accent bar</div>
<div class="border-x border-gray-300">Left & right</div>

<div class="border border-dashed border-gray-400">Dashed</div>
<div class="border border-dotted">Dotted</div>
<div class="border border-double">Double</div>

Border Radius

rounded-{none,sm,md,lg,xl,2xl,3xl,full} scale the radius; rounded-full makes pills or perfect circles (when width = height). Per-corner: rounded-{tl,tr,bl,br}-{size}, per-side: rounded-{t,b,l,r}-{size}. Avatar circles use rounded-full + w/h equal.

tailwind
<div class="rounded">0.25rem</div>
<div class="rounded-md">0.375rem</div>
<div class="rounded-lg">0.5rem</div>
<div class="rounded-xl">0.75rem</div>
<div class="rounded-2xl">1rem</div>
<div class="rounded-full">Fully rounded (pill/circle)</div>

<div class="rounded-t-lg rounded-b-none">Top only</div>
<div class="rounded-l-full">Left side pill</div>
<div class="rounded-tr-2xl rounded-bl-2xl">Per-corner</div>

Divide Between Children

divide-{x,y} adds borders between siblings — much cleaner than styling each child with border-t. divide-{color} and divide-{width} customize them. Pair with py/px on children for comfortable spacing in lists and tables.

tailwind
<ul class="divide-y divide-gray-200">
  <li class="py-2">Item 1</li>
  <li class="py-2">Item 2</li>
  <li class="py-2">Item 3</li>
</ul>
<!-- Adds a 1px top border to each child except the first -->

<div class="flex divide-x divide-gray-300">
  <div class="px-4">Col 1</div>
  <div class="px-4">Col 2</div>
  <div class="px-4">Col 3</div>
</div>

Ring (Outline-like)

Rings are box-shadow-based outlines that don't affect layout (unlike borders) and overlap nicely. ring-{n} sets width, ring-{color} the color, ring-offset-{n} adds whitespace between element and ring. The focus:ring pattern is the standard accessible focus style.

tailwind
<button class="ring-2 ring-blue-500 ring-offset-2">
  Ring with offset
</button>

<input class="ring-2 ring-red-500 focus:ring-2 focus:ring-blue-500" />

<button class="ring-1 ring-inset ring-gray-300">Inset ring</button>

<!-- Focus ring pattern (accessibility) -->
<button class="focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2">
  Accessible focus
</button>

Outline

outline-* uses the real CSS outline property (outside the border box, no layout impact). Ring is preferred in Tailwind because it's a layered box-shadow — multiple rings can stack and ring-offset gives a clean gap. Outline is useful when you explicitly need the CSS outline behavior.

tailwind
<input class="outline-none" />  <!-- Remove default -->
<input class="outline outline-2 outline-blue-500" />
<input class="outline-dashed outline-1 outline-gray-400" />

<input class="focus:outline-none focus:ring-2 focus:ring-blue-500"
       type="text" />

<!-- Outline vs ring: outline is drawn outside border-box,
     ring is a box-shadow (can stack, has offset) -->
08

Backgrounds

Background Color & Attachment

bg-{color} sets background-color, with /{opacity} for alpha. bg-fixed creates a parallax effect (background stays put while content scrolls). bg-clip-{padding,border,content} controls how far the background extends under borders/content.

tailwind
<div class="bg-blue-500">Solid color</div>
<div class="bg-blue-500/50">50% opacity</div>
<div class="bg-fixed">Parallax (fixed on scroll)</div>
<div class="bg-local">Scrolls with content</div>
<div class="bg-scroll">Default</div>

<!-- Clip: padding-box, border-box, content-box -->
<div class="bg-clip-padding border-4 border-dashed">Padding clip</div>
<div class="bg-clip-border">Border clip</div>

Background Image & Gradient

Use bg-[url('/path/to/img.jpg')] for background-image with arbitrary URLs (quote the URL). bg-cover fills the element while keeping aspect ratio; bg-contain fits the whole image. bg-{center,top,bottom,left,right} and bg-{repeat,no-repeat,repeat-x,repeat-y} control positioning.

tailwind
<div class="bg-gradient-to-r from-cyan-500 to-blue-500">
  Horizontal gradient
</div>

<!-- Image with arbitrary value -->
<div class="bg-[url('/hero.jpg')] bg-cover bg-center h-64">
  Hero with cover image
</div>

<!-- Repeat & position -->
<div class="bg-repeat-x bg-[url('/pattern.png')]">Repeat horizontally</div>
<div class="bg-no-repeat bg-top">No repeat, top aligned</div>

Gradient Direction & Stops

from-/via-/to- set gradient color stops; bg-gradient-to-{direction} sets the angle. Diagonal directions like to-br are common for warm hero gradients. Native radial/conic gradients need a plugin or arbitrary value: bg-[radial-gradient(...)].

tailwind
<!-- Directions: to-t, to-b, to-l, to-r, to-tr, to-tl, to-br, to-bl -->
<div class="bg-gradient-to-br from-amber-400 to-orange-600">
  Bottom-right diagonal
</div>

<!-- Three-stop gradient -->
<div class="bg-gradient-to-r from-green-400 via-teal-500 to-blue-600">
  Multi-stop
</div>

<!-- Radial (Tailwind v3.3+) -->
<div class="bg-gradient-radial from-pink-400 to-purple-700">
  Radial (may need plugin)
</div>

Background Size & Position

bg-cover vs bg-contain is the key choice for hero images and logos respectively. Cover fills the box (crops overflow); contain fits the whole image (may show empty space). Combine bg-cover + bg-center for the standard responsive hero image.

tailwind
<div class="bg-cover bg-center h-48 bg-[url('/img.jpg')]">
  Cover: fills container, may crop
</div>

<div class="bg-contain bg-center h-48 bg-no-repeat bg-[url('/logo.png')]">
  Contain: fits entire image, may letterbox
</div>

<div class="bg-top-left bg-[url('/img.jpg')] bg-cover">Top-left anchor</div>
<div class="bg-[center_top]">Custom position</div>

Background Blend Modes

bg-blend-{mode} controls how multiple background layers (image + color) composite. multiply, screen, overlay, darken, lighten are common. For darkening images for text legibility, the cleaner approach is a semi-transparent gradient overlay on top (right example).

tailwind
<div class="bg-blend-multiply bg-[url('/photo.jpg')] bg-blue-500">
  Multiplies image with blue overlay
</div>

<!-- Common overlay pattern: dark gradient over image -->
<div class="relative">
  <img src="/hero.jpg" class="w-full" />
  <div class="absolute inset-0 bg-gradient-to-t from-black/70 to-transparent">
    Overlay
  </div>
</div>
09

Shadows

Box Shadow Scale

The shadow scale (sm, default, md, lg, xl, 2xl) gives consistent elevation across your app. shadow-inner creates an inset shadow useful for wells and pressed states. Cards typically use shadow-md with hover:shadow-lg for a lift effect.

tailwind
<div class="shadow-sm">Subtle</div>
<div class="shadow">Default</div>
<div class="shadow-md">Medium</div>
<div class="shadow-lg">Large</div>
<div class="shadow-xl">Extra large</div>
<div class="shadow-2xl">Huge</div>
<div class="shadow-none">No shadow</div>

<!-- Inner shadow -->
<div class="shadow-inner">Pressed-in look</div>

Colored Shadows

shadow-{color} tints the box shadow with a color (uses the same color palette). Combined with /{opacity} it creates glow effects. Colored shadows are a quick way to make buttons and accents feel more vibrant and branded.

tailwind
<div class="shadow-lg shadow-blue-500/50">
  Blue tinted shadow
</div>

<div class="shadow-xl shadow-cyan-500/30">
  Cyan glow effect
</div>

<div class="shadow-md shadow-black/30">Darker default</div>

<button class="bg-emerald-500 shadow-lg shadow-emerald-500/50">
  Colored button shadow
</button>

Hover Lift Pattern

hover:shadow-{larger} combined with transition-shadow is the standard card-hover pattern. Pairing it with hover:-translate-y-0.5 and active:translate-y-0 gives a button physical press feedback — a tiny but satisfying interaction polish.

tailwind
<div class="bg-white rounded-xl shadow-md hover:shadow-xl
            transition-shadow duration-300 p-6 cursor-pointer">
  Card with hover lift
</div>

<!-- Combined with slight translate for tactile feel -->
<button class="shadow-md hover:shadow-sm active:shadow-sm
               hover:-translate-y-0.5 active:translate-y-0
               transition-all">
  Tactile button
</button>

Drop Shadow (for SVG/text)

drop-shadow uses CSS filter:drop-shadow() which follows the actual shape of the element (great for SVGs and PNGs with transparency), unlike box-shadow which only shadows the box. drop-shadow-md on text is a softer alternative to text-shadow.

tailwind
<h1 class="drop-shadow-md">Text with shadow</h1>

<svg class="drop-shadow-lg">
  <!-- SVG shape gets shadowed as a whole -->
</svg>

<!-- Combine with rotate for dramatic effects -->
<div class="rotate-3 drop-shadow-2xl">Tilted card</div>

<!-- Filter utilities affect the element as a whole image -->
<div class="blur-sm brightness-110">Image filters</div>

Arbitrary & Layered Shadows

For shadows outside the default scale, use arbitrary value syntax shadow-[...]. For complex layered shadows (the kind that look truly premium), it's cleaner to define them once in a custom CSS class — Tailwind's single-layer shadows can't match multi-layer depth.

tailwind
<div class="shadow-[0_8px_30px_rgb(0,0,0,0.12)]">
  Custom shadow via arbitrary value
</div>

<!-- Multiple layered shadows via custom CSS -->
<style>
  .card-shadow {
    box-shadow:
      0 1px 2px rgba(0,0,0,0.04),
      0 4px 8px rgba(0,0,0,0.06),
      0 12px 24px rgba(0,0,0,0.08);
  }
</style>
<div class="card-shadow">Layered elevation</div>
10

Responsive Design

Breakpoints

Tailwind is mobile-first: base styles apply everywhere, breakpoint prefixes apply at min-width. Order matters — write classes from smallest to largest (text-sm md:text-base lg:text-lg). The breakpoints match common device widths and are configurable.

tailwind
<!-- Default = mobile first, then min-width overrides -->
<!-- sm: 640px, md: 768px, lg: 1024px, xl: 1280px, 2xl: 1536px -->

<div class="text-sm md:text-base lg:text-lg">
  Grows with viewport
</div>

<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4">
  Responsive grid
</div>

<!-- Hide on small screens, show on large -->
<div class="hidden md:block">Desktop only</div>
<div class="block md:hidden">Mobile only</div>

Responsive Flex/Grid

The flex-col md:flex-row pattern is the backbone of responsive layouts: stack vertically on phones, side-by-side on desktops. Pair with responsive grid-cols-* for card grids. Always design the mobile layout first, then enhance upward.

tailwind
<!-- Stack on mobile, row on desktop -->
<div class="flex flex-col md:flex-row gap-4">
  <aside class="md:w-64">Sidebar</aside>
  <main class="flex-1">Main</main>
</div>

<!-- 1 col mobile -> 2 col tablet -> 4 col desktop -->
<div class="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-4 gap-4">
  <div>Card</div>
</div>

<!-- Sidebar that hides on mobile -->
<aside class="hidden lg:block lg:w-1/4">Sidebar</aside>

Container & Max Width

container centers content with responsive max-widths at each breakpoint (needs centering + padding added manually). The manual pattern 'max-w-7xl mx-auto px-4 sm:px-6 lg:px-8' is the most common page wrapper. For articles, cap at max-w-2xl/3xl for readable line lengths.

tailwind
<div class="container mx-auto px-4">
  <!-- Centers content and caps width at each breakpoint -->
</div>

<!-- Or manually cap width -->
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
  Standard page wrapper
</div>

<article class="prose max-w-none lg:max-w-2xl mx-auto">
  Article with readable line length
</article>

Show/Hide by Breakpoint

hidden md:block / block md:hidden is the canonical pattern for toggling elements between mobile and desktop (e.g. hamburger menu vs full nav). print:block shows only when printing. Arbitrary breakpoints like min-[1200px]: let you target custom widths.

tailwind
<!-- Mobile-only nav -->
<nav class="block md:hidden">Mobile menu</nav>

<!-- Desktop-only nav -->
<nav class="hidden md:flex">Desktop menu</nav>

<!-- Hide print-only content -->
<div class="hidden print:block">Only shows when printing</div>

<!-- Custom breakpoint -->
<div class="min-[1200px]:flex">Custom MQ</div>

Responsive Typography & Spacing

Scale typography and spacing up at each breakpoint for visual hierarchy. For truly fluid type, use clamp() via arbitrary value: text-[clamp(2rem,5vw,4rem)] — the heading smoothly grows with the viewport between min and max.

tailwind
<h1 class="text-3xl sm:text-4xl md:text-5xl lg:text-6xl
         font-bold leading-tight">
  Fluid-ish heading
</h1>

<section class="px-4 sm:px-6 lg:px-12 py-8 md:py-12 lg:py-20">
  Scales padding with viewport
</section>

<!-- True fluid type with clamp via arbitrary value -->
<h1 class="text-[clamp(2rem,5vw,4rem)]">
  Smoothly scales with viewport
</h1>
11

Dark Mode

Enable Dark Mode (class strategy)

By default Tailwind uses prefers-color-scheme (media). Setting darkMode:'class' lets you toggle dark mode by adding the 'dark' class to a parent (typically <html>) — needed for theme switchers. darkMode:'selector' (v3.4+) is similar but supports custom selectors.

tailwind
// tailwind.config.js
module.exports = {
  darkMode: "class",  // default is "media" (prefers-color-scheme)
  // ...
};

<!-- Toggle by adding/removing "dark" on <html> -->
<html class="dark">
  <body class="bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100">
    Auto-styled in dark
  </body>
</html>

Dark Variants

Prefix any utility with dark: to apply it only in dark mode. The pattern is to write the light style first, then dark: overrides. Be systematic: pair every bg-*, text-*, border-* with a dark:* equivalent so nothing looks broken in dark mode.

tailwind
<div class="bg-white dark:bg-gray-800
            text-gray-900 dark:text-gray-100
            border-gray-200 dark:border-gray-700">
  Adapts to theme
</div>

<button class="bg-blue-600 dark:bg-blue-500
               hover:bg-blue-700 dark:hover:bg-blue-600">
  Themed button
</button>

Theme Toggle Script

Put this inline script in <head> before the page renders to avoid a flash of the wrong theme (FOUC). It checks localStorage first, then falls back to the OS preference. The toggle just flips the class and persists the choice.

tailwind
// Check stored preference or system preference on load
if (localStorage.theme === 'dark' ||
    (!('theme' in localStorage) &&
     window.matchMedia('(prefers-color-scheme: dark)').matches)) {
  document.documentElement.classList.add('dark');
} else {
  document.documentElement.classList.remove('dark');
}

// Toggle button handler
function toggleTheme() {
  document.documentElement.classList.toggle('dark');
  localStorage.theme = document.documentElement.classList.contains('dark')
    ? 'dark' : 'light';
}

System Preference Only

If you don't need a manual toggle, darkMode:'media' (the default) follows the user's OS setting with zero JavaScript. Simpler, but you lose the ability to override the preference. Use this for content sites where respecting the OS choice is sufficient.

tailwind
// tailwind.config.js
module.exports = {
  darkMode: "media",  // follow prefers-color-scheme automatically
  // ...
};

<!-- dark: utilities apply when OS is in dark mode -->
<div class="bg-white dark:bg-gray-900">
  No toggle, just follows the OS
</div>

<!-- Force a specific theme by not using dark: at all
     (the dark styles simply never apply) -->

Dark Mode Best Practices

Good dark mode isn't just color inversion: use dark gray (gray-900) not pure black for backgrounds, off-white (gray-100) not pure white for text, dim images slightly, and reduce or remove shadows. Saturated brand colors often need to be lightened (blue-600 -> blue-500) in dark mode.

tailwind
<!-- Don't just invert — lower contrast and saturation -->
<div class="bg-white dark:bg-gray-900     <!-- not black -->
            text-gray-900 dark:text-gray-100 <!-- not pure white -->
            shadow-lg dark:shadow-none">     <!-- shadows look off in dark -->

<!-- Dim images slightly in dark mode -->
<img class="dark:opacity-90 dark:brightness-90" src="/photo.jpg" />

<!-- Reduce border intensity -->
<div class="border-gray-200 dark:border-gray-800">...</div>
12

Animations & Transitions

Transitions

transition-{property} defines which properties animate; duration-{ms} sets the time; ease-{in,out,in-out} sets the timing function. transition-colors is the most common (cheaper than transition-all). Always add transition before the hover:* change or it'll snap.

tailwind
<button class="bg-blue-500 hover:bg-blue-600
               transition-colors duration-200">
  Color transition
</button>

<div class="transition-all duration-300 ease-in-out
            hover:scale-105 hover:shadow-lg">
  Multi-property transition
</div>

<div class="transition-opacity duration-500 opacity-50 hover:opacity-100">
  Fade in on hover
</div>

Transition Properties

Prefer specific transitions (transition-colors, transition-transform) over transition-all for performance — all watches every property and can cause jank. duration-* uses 75/100/150/200/300/500/700/1000ms. ease-out feels natural for UI elements appearing.

tailwind
<div class="transition-none">No animation</div>
<div class="transition-colors">bg/text/border-color</div>
<div class="transition-opacity">opacity only</div>
<div class="transition-shadow">box-shadow only</div>
<div class="transition-transform">scale/rotate/translate</div>
<div class="transition-all">Everything (heaviest)</div>

<!-- Duration & easing -->
<div class="duration-150">150ms</div>
<div class="duration-700">700ms</div>
<div class="ease-linear">Linear</div>
<div class="ease-in">Accelerate</div>
<div class="ease-out">Decelerate</div>

Built-in Animations

Tailwind ships four keyframe animations: spin (loader), ping (expanding notification dot), pulse (opacity fade — perfect for skeleton loaders), bounce (playful). For custom animations, define keyframes in config and reference via animate-[name].

tailwind
<div class="animate-spin">Spinning loader</div>
<div class="animate-ping">Pulsing ping (notifications)</div>
<div class="animate-pulse">Fading pulse (skeleton loaders)</div>
<div class="animate-bounce">Bouncing arrow</div>

<!-- Skeleton loader pattern -->
<div class="animate-pulse bg-gray-200 rounded h-4 w-3/4"></div>
<div class="animate-pulse bg-gray-200 rounded h-4 w-1/2 mt-2"></div>

Transform

scale-, rotate-, translate-, skew- all compose and animate smoothly with transition-transform. Use origin-{center,top,bottom-left,...} to change the transform origin. Card hover flourishes (scale + slight rotate + lift) feel premium when kept subtle.

tailwind
<div class="hover:scale-110 transition-transform">Grow on hover</div>
<div class="hover:rotate-3">Tilt on hover</div>
<div class="hover:-translate-y-1">Lift on hover</div>
<div class="hover:skew-y-3">Skew on hover</div>

<!-- Combined -->
<div class="hover:scale-105 hover:-translate-y-1 hover:rotate-1
            transition-transform duration-300">
  Card flourish
</div>

<!-- Origin -->
<div class="origin-top-left rotate-12">Rotated from corner</div>

Custom Animations via Config

Define custom keyframes and animation names in theme.extend. The animation value is shorthand: '{name} {duration} {timing} {iteration}'. Once defined, animate-{name} becomes a normal utility. Keep keyframes small — they ship in your CSS bundle.

tailwind
// tailwind.config.js
module.exports = {
  theme: {
    extend: {
      keyframes: {
        wiggle: {
          "0%, 100%": { transform: "rotate(-3deg)" },
          "50%":      { transform: "rotate(3deg)" },
        },
      },
      animation: {
        wiggle: "wiggle 1s ease-in-out infinite",
      },
    },
  },
};

// Usage
<div class="animate-wiggle">Wiggling</div>
13

Forms

Input Fields

The standard input pattern: w-full for full width, padding, border, rounded, and a focus ring that removes the default outline. focus:border-transparent hides the native focus border; focus:ring-2 draws a clear accessible focus indicator. Always style disabled state for clarity.

tailwind
<input type="text"
       class="w-full px-3 py-2 border border-gray-300 rounded-md
              focus:outline-none focus:ring-2 focus:ring-blue-500
              focus:border-transparent
              placeholder-gray-400 text-gray-900"
       placeholder="Enter your name" />

<input type="email" disabled
       class="opacity-50 cursor-not-allowed" />

<textarea class="w-full rounded-md border-gray-300" rows="4"></textarea>

Checkboxes & Radios

text-{color} on checkboxes/radios sets the checked color (uses accent-color under the hood). focus:ring-* adds the keyboard focus indicator. For custom toggles, use the peer-* pattern with a hidden checkbox to drive the styling, or use a plugin like @tailwindcss/forms.

tailwind
<label class="flex items-center gap-2">
  <input type="checkbox" class="rounded border-gray-300
                                 text-blue-600 focus:ring-blue-500" />
  Accept terms
</label>

<label class="flex items-center gap-2">
  <input type="radio" name="plan"
         class="border-gray-300 text-blue-600 focus:ring-blue-500" />
  Free plan
</label>

<!-- Custom toggle switch -->
<button role="switch" aria-checked="false"
        class="relative w-11 h-6 rounded-full bg-gray-300
               peer-checked:bg-blue-600 transition-colors">
  <span class="absolute left-0.5 top-0.5 w-5 h-5 bg-white
               rounded-full transition-transform peer-checked:translate-x-5">
  </span>
</button>

Select & Options

Native <select> styling is limited cross-browser; for full control use a custom dropdown component or a library like Headless UI. The @tailwindcss/forms plugin gives all form elements a consistent, easily-themeable baseline — worth installing for any form-heavy app.

tailwind
<select class="w-full px-3 py-2 border border-gray-300 rounded-md
                bg-white text-gray-900 focus:ring-2 focus:ring-blue-500">
  <option value="">Choose...</option>
  <option value="us">United States</option>
  <option value="cn">China</option>
</select>

<!-- Multiple select -->
<select multiple class="h-32">
  <option>Tag 1</option>
  <option>Tag 2</option>
</select>

Form Layout

space-y-4 is the cleanest way to space a form's rows — no per-field margins needed. Pair each input with a <label class='block text-sm font-medium mb-1'> for consistent label styling. Wrap in max-w-md to keep form width readable on desktop.

tailwind
<form class="space-y-4 max-w-md">
  <div>
    <label class="block text-sm font-medium text-gray-700 mb-1">
      Email
    </label>
    <input type="email" class="w-full ..." />
  </div>
  <div>
    <label class="block text-sm font-medium text-gray-700 mb-1">
      Password
    </label>
    <input type="password" class="w-full ..." />
  </div>
  <button type="submit" class="w-full bg-blue-600 text-white py-2 rounded">
    Sign in
  </button>
</form>

Buttons

Buttons deserve active: (pressed), disabled: (state), and focus: (keyboard) variants — not just hover. active:bg-{darker} gives physical feedback. disabled:opacity-50 disabled:cursor-not-allowed is the standard disabled treatment. Keep a consistent height (e.g. py-2) across button variants.

tailwind
<button class="bg-blue-600 hover:bg-blue-700 active:bg-blue-800
               text-white font-medium py-2 px-4 rounded-md
               transition-colors focus:outline-none
               focus:ring-2 focus:ring-blue-500 focus:ring-offset-2">
  Primary
</button>

<button class="bg-white border border-gray-300 hover:bg-gray-50
               text-gray-700 py-2 px-4 rounded-md transition-colors">
  Secondary
</button>

<button class="text-blue-600 hover:text-blue-800 hover:underline">
  Ghost link button
</button>

<button class="bg-red-600 hover:bg-red-700 disabled:opacity-50
               disabled:cursor-not-allowed" disabled>
  Disabled
</button>
14

Cards

Basic Card

The canonical card: rounded + shadow + overflow-hidden (so the image corners clip nicely). object-cover on the image prevents distortion. hover:shadow-lg with transition-shadow gives the lift effect. overflow-hidden is key for rounded image tops.

tailwind
<div class="max-w-sm rounded-xl shadow-md overflow-hidden
            bg-white hover:shadow-lg transition-shadow">
  <img class="w-full h-48 object-cover" src="/photo.jpg" alt="" />
  <div class="p-6">
    <h3 class="text-xl font-semibold mb-2">Card title</h3>
    <p class="text-gray-600">Card description goes here.</p>
    <button class="mt-4 text-blue-600 font-medium hover:underline">
      Learn more
    </button>
  </div>
</div>

Card Grid

For card grids, use the auto-fill + minmax pattern: cards are at least 280px and stretch to fill, wrapping automatically — no media queries. For fixed column counts at known breakpoints, the responsive grid-cols-* approach is simpler to reason about.

tailwind
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3
            gap-6">
  <div class="rounded-xl shadow p-6 bg-white">Card 1</div>
  <div class="rounded-xl shadow p-6 bg-white">Card 2</div>
  <div class="rounded-xl shadow p-6 bg-white">Card 3</div>
  <div class="rounded-xl shadow p-6 bg-white">Card 4</div>
</div>

<!-- Auto-fit grid for variable width -->
<div class="grid gap-6
            grid-cols-[repeat(auto-fill,minmax(280px,1fr))]">
  <!-- Cards naturally wrap based on viewport -->
</div>

Interactive Card (whole clickable)

Wrapping the whole card in an <a> makes it entirely clickable (better UX than a separate 'Read more' button). The group + group-hover pattern lets you animate child elements (the title color, the arrow position) when the parent is hovered — powerful for interactive cards.

tailwind
<a href="/post" class="group block max-w-sm rounded-xl
         shadow-md hover:shadow-xl transition-shadow bg-white">
  <div class="p-6">
    <h3 class="font-semibold group-hover:text-blue-600 transition-colors">
      Card title
    </h3>
    <p class="text-gray-600 mt-2">Description...</p>
    <span class="mt-4 inline-flex items-center text-blue-600">
      Read more
      <svg class="w-4 h-4 ml-1 group-hover:translate-x-1 transition-transform">
        <!-- arrow icon path -->
      </svg>
    </span>
  </div>
</a>

Card with Footer

Use flex flex-col on the card and flex-1 on the body to make the footer stick to the bottom even when card bodies have different lengths — keeps a row of cards aligned. The footer typically has metadata and actions with a subtle bg and top border.

tailwind
<div class="max-w-sm rounded-xl shadow bg-white flex flex-col">
  <div class="p-6 flex-1">
    <h3 class="text-lg font-semibold">Title</h3>
    <p class="text-gray-600 mt-2">Body content...</p>
  </div>
  <div class="px-6 py-4 bg-gray-50 border-t border-gray-100
              flex justify-between items-center">
    <span class="text-sm text-gray-500">Aug 12, 2025</span>
    <button class="text-sm text-blue-600 hover:underline">Share</button>
  </div>
</div>

Profile / Avatar Card

Avatar + name + action is the standard row-card pattern. Use flex items-center gap-4 to align them. For status dots, position absolute bottom-right with a ring matching the card bg to 'cut out' the dot. Avatars use rounded-full + equal w/h + object-cover.

tailwind
<div class="flex items-center gap-4 p-4 rounded-xl shadow bg-white">
  <img src="/avatar.jpg"
       class="w-12 h-12 rounded-full object-cover" alt="" />
  <div class="flex-1">
    <p class="font-semibold">Alice Zhang</p>
    <p class="text-sm text-gray-500">Software Engineer</p>
  </div>
  <button class="text-blue-600 text-sm font-medium">Follow</button>
</div>

<!-- Status indicator -->
<div class="relative">
  <img class="w-10 h-10 rounded-full" src="/avatar.jpg" />
  <span class="absolute bottom-0 right-0 w-3 h-3
               bg-green-500 rounded-full ring-2 ring-white"></span>
</div>
16

Layout Patterns

Position

relative + absolute is the workhorse: set position:relative on a parent and position:absolute on a child to place it precisely. inset-0 = top/right/bottom/left:0 (fills the parent). sticky top-0 is essential for sticky headers — needs the parent to be tall enough to scroll.

tailwind
<div class="static">Default flow</div>
<div class="relative">
  <div class="absolute top-0 right-0">Top-right of parent</div>
</div>
<div class="fixed bottom-4 right-4">Stuck to viewport</div>
<div class="sticky top-0">Sticks when scrolling</div>

<!-- Inset shorthand for all sides -->
<div class="absolute inset-0">Fills parent</div>
<div class="absolute inset-x-0 bottom-0">Full width, at bottom</div>

Z-Index & Stacking

Tailwind provides z-0/10/20/30/40/50 plus z-auto. Use a consistent convention: 0 = base, 10 = dropdowns, 20 = sticky, 30 = modals, 40 = overlays, 50 = toasts/tooltips. Modals need both a high z-index AND fixed inset-0 to cover the viewport.

tailwind
<div class="z-0">Base layer</div>
<div class="z-10">Dropdowns</div>
<div class="z-20">Sticky headers</div>
<div class="z-30">Modals</div>
<div class="z-40">Overlays</div>
<div class="z-50">Tooltips, toasts</div>

<!-- Combine with relative/absolute/fixed -->
<div class="fixed inset-0 z-50 bg-black/50">Modal overlay</div>

Display

block/inline-block/inline/hidden are the basics. inline-block is useful for elements that need width/height but should sit inline. hidden removes from layout entirely (vs opacity-0 which keeps the space). Toggle with breakpoint prefixes for responsive show/hide.

tailwind
<div class="block">Full-width block</div>
<div class="inline-block">Inline with set width/height</div>
<div class="inline">Flows inline</div>
<div class="hidden">Removed from layout</div>
<div class="flex">Flex container</div>
<div class="grid">Grid container</div>

<!-- Toggle on breakpoint -->
<div class="hidden md:block">Hidden on mobile</div>
<div class="block md:hidden">Hidden on desktop</div>

<!-- Tables, contents, list-item also available -->

Overflow

overflow-hidden clips content (also used to make rounded corners clip children). overflow-auto adds scrollbars only when needed; overflow-x-auto with whitespace-nowrap is the standard horizontal-scroll pattern for nav rows and code blocks.

tailwind
<div class="overflow-hidden">Clips overflow</div>
<div class="overflow-auto">Scrollbars if needed</div>
<div class="overflow-scroll">Always scrollable</div>
<div class="overflow-visible">Default, overflows</div>

<!-- Per-axis -->
<div class="overflow-x-auto whitespace-nowrap">Horizontal scroll</div>
<div class="overflow-y-auto h-64">Vertical scroll area</div>

<!-- Hide scrollbars while keeping scroll (Webkit) -->
<div class="overflow-x-auto scrollbar-hide">...</div>

Float & Clear

Floats are largely replaced by flexbox/grid for layout, but float-left + mr-4 still works well for text wrapping around images. For most image sizing needs, object-cover (fills, may crop) or object-contain (fits, may letterbox) on an img with set dimensions is the modern approach.

tailwind
<img class="float-left mr-4 rounded" src="/photo.jpg" />
<p>Text wraps around the floated image on the right...</p>
<p class="clear-both">After the float</p>

<!-- Floats are mostly legacy; prefer flex/grid for layout.
     Still useful for text wrapping around images. -->

<!-- Object fit for responsive images -->
<img class="w-full h-48 object-cover" src="/hero.jpg" />
<img class="w-24 h-24 object-contain" src="/logo.png" />
17

Effects & Filters

Backdrop Blur (glassmorphism)

backdrop-blur-* blurs whatever is behind the element (not the element itself) — combined with a translucent bg (bg-white/30) it creates the glassmorphism effect. Perfect for modals, sticky headers over content, and iOS-style frosted panels.

tailwind
<div class="backdrop-blur-md bg-white/30 border border-white/20
            rounded-xl p-6 shadow-lg">
  Frosted glass card
</div>

<!-- Strengths -->
<div class="backdrop-blur-sm">Light blur</div>
<div class="backdrop-blur-md">Medium</div>
<div class="backdrop-blur-xl">Heavy</div>
<div class="backdrop-blur-2xl">Maximum</div>

<!-- Modal overlay with blur -->
<div class="fixed inset-0 bg-black/50 backdrop-blur-sm z-50">
  Overlay with frosted bg
</div>

Image Filters

Filter utilities map to CSS filter functions: blur, brightness, contrast, grayscale, invert, sepia, saturate, hue-rotate. The grayscale hover:grayscale-0 pattern is a popular effect for team photos and product images — color appears on hover.

tailwind
<img class="blur-sm" src="/photo.jpg" />
<img class="blur-md" src="/photo.jpg" />
<img class="brightness-110" src="/photo.jpg" />
<img class="contrast-125" src="/photo.jpg" />
<img class="grayscale" src="/photo.jpg" />
<img class="invert" src="/photo.jpg" />
<img class="sepia" src="/photo.jpg" />
<img class="saturate-150" src="/photo.jpg" />

<!-- Combined + hover -->
<img class="grayscale hover:grayscale-0 transition-all duration-500"
     src="/photo.jpg" />

Mix Blend Mode

mix-blend-mode controls how an element blends with what's behind it. mix-blend-difference on white text over an image creates a high-contrast effect that's readable regardless of the underlying image — popular for hero sections. Use sparingly; it can look gimmicky.

tailwind
<div class="mix-blend-multiply">Multiplies with bg</div>
<div class="mix-blend-screen">Lightens</div>
<div class="mix-blend-overlay">Contrast blend</div>
<div class="mix-blend-difference">Inverts colors</div>

<!-- Text over image with blend -->
<div class="relative">
  <img src="/photo.jpg" />
  <h1 class="absolute inset-0 flex items-center justify-center
             text-white mix-blend-difference text-6xl font-bold">
    Overlay text
  </h1>
</div>

Opacity

opacity-{0,25,50,75,100} (plus 5/10/20/.../95) sets element opacity — affects the element AND its children. For just a translucent background use bg-{color}/{opacity} instead, which keeps text fully opaque. opacity-0 hides but preserves layout (vs hidden which removes it).

tailwind
<div class="opacity-100">Fully visible</div>
<div class="opacity-75">75%</div>
<div class="opacity-50">Half</div>
<div class="opacity-25">Mostly transparent</div>
<div class="opacity-0">Invisible (still takes space)</div>

<!-- Hover fade -->
<button class="opacity-100 hover:opacity-80 transition-opacity">
  Fades on hover
</button>

<!-- vs bg-black/50: opacity affects the whole element
     (including children), bg color/opacity only the background -->

Cursor & User Select

Always match cursor to behavior: cursor-pointer for clickable, cursor-not-allowed for disabled. select-none disables text selection (useful for UI chrome and double-click-prone buttons). resize-none on textareas prevents the default resize handle when you want consistent layout.

tailwind
<button class="cursor-pointer">Pointer on hover</button>
<div class="cursor-not-allowed opacity-50">Disabled</div>
<div class="cursor-move">Drag handle</div>
<div class="cursor-text">Text input area</div>

<!-- Selection -->
<p class="select-none">Cannot be selected</p>
<p class="select-text">Selectable text</p>
<p class="select-all">Selects all on click</p>

<!-- Resize handle -->
<textarea class="resize-none"></textarea>
<textarea class="resize-y"></textarea>
18

Transitions & Transforms

Transform Origin & Scale

origin-* sets the transform origin point. scale-x-* / scale-y-* scale independently per axis. transform-gpu forces GPU acceleration (translate3d) for smoother animations — use it when you see jank on transform-heavy elements like carousels.

tailwind
<div class="origin-center scale-110">Center origin (default)</div>
<div class="origin-top-left scale-90">Top-left origin</div>
<div class="origin-bottom rotate-45">Bottom origin, rotated</div>

<!-- Combined transforms -->
<div class="transform-gpu hover:scale-105 hover:rotate-3
            transition-transform duration-300">
  GPU-accelerated flourish
</div>

<!-- Independent scale axes -->
<div class="hover:scale-x-110">Stretches horizontally</div>
<div class="hover:scale-y-90">Squishes vertically</div>

Translate & Rotate

translate-{x,y}-{n} moves the element using the spacing scale (or use /2 for 50% via -translate-x-1/2). The left-1/2 + -translate-x-1/2 pattern perfectly centers an absolutely-positioned element regardless of its width — useful for tooltips and modals.

tailwind
<div class="translate-x-4">16px right</div>
<div class="-translate-x-4">16px left</div>
<div class="translate-y-2">8px down</div>
<div class="rotate-45">45deg clockwise</div>
<div class="-rotate-12">12deg counter-clockwise</div>
<div class="rotate-180">Flipped</div>

<!-- Centering trick: absolute + translate -->
<div class="absolute left-1/2 top-1/2
            -translate-x-1/2 -translate-y-1/2">
  Perfectly centered
</div>

Skew & 3D Transforms

Skew tilts an element along an axis — useful for subtle parallelogram effects. 3D transforms (perspective, rotate-y, rotate-x, transform-style-3d) need theme extension in default Tailwind but enable card-flip and parallax effects. Most projects just use 2D transforms.

tailwind
<div class="skew-x-12">Skewed horizontally</div>
<div class="skew-y-6">Skewed vertically</div>
<div class="-skew-x-6">Counter skew</div>

<!-- 3D (needs perspective on parent) -->
<div class="perspective-1000">
  <div class="rotate-y-12 transform-style-3d">Tilted in 3D</div>
</div>

<!-- Card flip pattern -->
<div class="preserve-3d group hover:rotate-y-180
            transition-transform duration-700">
  Flips on hover (needs config)
</div>

Transition Delay & Timing

delay-{ms} delays the start of a transition — combine with per-child delays to create staggered entrances (each item starts slightly later). ease-out feels natural for things appearing (decelerate into place), ease-in for things disappearing (accelerate away).

tailwind
<div class="transition-colors duration-300 delay-150
            hover:bg-blue-500">
  Starts after 150ms
</div>

<!-- Stagger children via inline delay style -->
<div class="flex gap-2">
  <div class="transition-all delay-0 duration-500">A</div>
  <div class="transition-all delay-100 duration-500">B</div>
  <div class="transition-all delay-200 duration-500">C</div>
</div>

<!-- Easing -->
<div class="ease-in-out">Smooth</div>
<div class="ease-out">Decelerate (good for entrances)</div>
<div class="ease-in">Accelerate (good for exits)</div>

Hover vs Focus vs Active States

Always consider focus (keyboard users) and active (mouse-down) in addition to hover. focus-visible: applies only when keyboard-focused (not mouse click) — usually what you want for focus rings. group + group-hover: lets parent hover drive child styling — essential for cards and complex hovers.

tailwind
<button class="bg-blue-500
               hover:bg-blue-600   <!-- mouse over -->
               focus:bg-blue-700   <!-- keyboard focus -->
               active:bg-blue-800  <!-- mouse down -->
               focus:outline-none focus:ring-2 focus:ring-blue-300
               transition-colors">
  All states styled
</button>

<!-- Group hover: style children when parent hovered -->
<div class="group">
  <button class="group-hover:scale-110 transition-transform">
    Scales when parent hovered
  </button>
</div>
19

Sizing

Width Scale

w-* uses the spacing scale plus fractions (1/2, 1/3, 2/3, 1/4, 3/4, 1/5, ..., 1/12) for percentages. w-full = 100%, w-screen = 100vw, w-fit = intrinsic width, w-max = max-content. Use w-full + max-w-{size} for responsive content that caps at a readable width.

tailwind
<div class="w-0">0</div>
<div class="w-px">1px</div>
<div class="w-1">0.25rem</div>
<div class="w-4">1rem (16px)</div>
<div class="w-16">4rem (64px)</div>
<div class="w-64">16rem</div>
<div class="w-96">24rem</div>

<!-- Fractions -->
<div class="w-1/2">50%</div>
<div class="w-1/3">33.33%</div>
<div class="w-2/3">66.67%</div>
<div class="w-full">100%</div>
<div class="w-screen">100vw</div>

Height & Viewport

h-screen = 100vh which has mobile browser address-bar issues. Prefer h-dvh (dynamic viewport height) for mobile-friendly full-height layouts — it adjusts as the browser chrome shows/hides. min-h-screen is the standard for sticky-footer layouts.

tailwind
<div class="h-8">2rem</div>
<div class="h-64">16rem</div>
<div class="h-full">100% of parent</div>
<div class="h-screen">100vh (full viewport)</div>

<!-- Modern viewport units (v3.4+) -->
<div class="h-dvh">Dynamic viewport height (mobile-friendly)</div>
<div class="h-svh">Small viewport height</div>
<div class="h-lvh">Large viewport height</div>

<!-- min/max -->
<div class="min-h-screen">At least viewport tall</div>
<div class="max-h-96 overflow-y-auto">Capped scroll area</div>

Min/Max Width

max-w-{xs,sm,md,lg,xl,2xl,...,7xl} map to rem-based sizes ideal for content width. Wrapping page content in max-w-7xl mx-auto is standard. min-w-0 is a critical flexbox trick — it lets flex children shrink below their intrinsic size to prevent overflow.

tailwind
<!-- Max-width is the key to readable content -->
<article class="max-w-2xl mx-auto">
  Caps article at ~42rem (readable line length)
</article>

<!-- Common max-widths -->
<div class="max-w-sm">384px</div>
<div class="max-w-md">28rem</div>
<div class="max-w-lg">32rem</div>
<div class="max-w-xl">36rem</div>
<div class="max-w-7xl">80rem</div>

<!-- min-width for inputs etc -->
<input class="min-w-0" />  <!-- prevent flex overflow -->
<div class="min-w-full">Always at least full width</div>

Aspect Ratio

aspect-{ratio} maintains a fixed aspect ratio regardless of width — far cleaner than the old padding-bottom hack. aspect-video is the standard for video embeds. Combine with object-cover to fill the box without distortion. Arbitrary ratios like aspect-[21/9] work too.

tailwind
<div class="aspect-square">1:1 square</div>
<div class="aspect-video">16:9 widescreen</div>
<div class="aspect-[4/3]">4:3</div>
<div class="aspect-[21/9]">Ultrawide</div>

<!-- Responsive video embed -->
<div class="aspect-video w-full">
  <iframe class="w-full h-full" src="..."></iframe>
</div>

<!-- Avatar / product image -->
<img class="aspect-square object-cover w-24" />

Object Fit & Position

object-fit on <img> (and <video>) controls how the source fills its box: cover (fill, crop), contain (fit, letterbox), fill (stretch), none (original size). Pair with object-{position} to control which part is kept when cropping. object-cover + object-center is the default for hero images.

tailwind
<img class="w-full h-48 object-cover" src="/hero.jpg" />
<!-- Fills the box, may crop. Best for hero images. -->

<img class="w-full h-48 object-contain" src="/logo.png" />
<!-- Fits entire image, may letterbox. Best for logos. -->

<img class="w-full h-48 object-fill" src="/img.jpg" />
<!-- Stretches to fill (distorts). Rarely what you want. -->

<img class="w-full h-48 object-none" src="/img.jpg" />
<!-- Keeps original size, may overflow. -->

<!-- Position -->
<img class="object-cover object-top" src="/portrait.jpg" />
<img class="object-cover object-center" src="/photo.jpg" />
20

Interactivity & State

Hover, Focus & Group

group turns an element into a state source; group-hover:* applies a style to a child when the parent is hovered. Crucial for cards where hovering the card affects the image, title, and a hidden action all at once. Named groups (group/card) allow nesting.

tailwind
<button class="hover:bg-blue-600">Hover state</button>
<input class="focus:ring-2 focus:ring-blue-500" />
<div class="active:scale-95">Press feedback</div>

<!-- group / group-hover: style children based on parent state -->
<div class="group">
  <img class="group-hover:scale-110 transition-transform" />
  <h3 class="group-hover:text-blue-600">Title</h3>
  <p class="opacity-0 group-hover:opacity-100">Revealed on hover</p>
</div>

Peer (sibling state)

peer marks an element as a state source for its SIBLINGS (only later siblings, by default). peer-checked:* lets you style siblings based on a checkbox/radio state — powers CSS-only toggles, password-reveal buttons, and accordions without JavaScript.

tailwind
<!-- Style a sibling based on an input's state -->
<input type="checkbox" id="c" class="peer" />
<label for="c" class="peer-checked:text-blue-600">
  Styled when checkbox checked
</label>

<!-- Show/hide password -->
<input type="checkbox" id="show" class="peer hidden" />
<label for="show" class="peer-checked:hidden">Show</label>
<label for="show" class="hidden peer-checked:inline">Hide</label>

<!-- Toggle a panel -->
<input type="checkbox" class="peer hidden" />
<div class="hidden peer-checked:block">Toggleable panel</div>

Focus-Visible (keyboard only)

Use focus-visible: instead of focus: for focus rings — it shows the ring only for keyboard users (who need it) and hides it for mouse clicks (which have their own visual feedback). Pair with focus:outline-none to suppress the default browser ring.

tailwind
<button class="focus:outline-none
               focus-visible:ring-2 focus-visible:ring-blue-500">
  No ring on mouse click, ring on keyboard focus
</button>

<!-- Why focus-visible: -->
<!-- - focus: applies on BOTH mouse click and keyboard
     (annoying for mouse users)
   - focus-visible: only on keyboard navigation
     (the accessible choice for focus rings) -->

Placeholder & File Input

placeholder-* styles the placeholder text. file:* styles the pseudo-button inside <input type='file'> — a notoriously hard element to style, but Tailwind's file: variant makes it tractable. The pattern above gives a clean, branded file upload button.

tailwind
<input class="placeholder-gray-400 placeholder-italic"
       placeholder="Type here..." />

<!-- Style the file input button -->
<input type="file"
       class="block w-full text-sm text-gray-500
              file:mr-4 file:py-2 file:px-4
              file:rounded-md file:border-0
              file:text-sm file:bg-blue-50
              file:text-blue-700
              hover:file:bg-blue-100" />

Marker & Selection

marker:* styles list bullets/numbers. selection:* styles the highlight when users select text. first-letter:* / first-line:* enable drop caps and small-caps first lines — useful for editorial designs. All these pseudo-elements have dedicated Tailwind variants.

tailwind
<ul class="marker:text-blue-500 list-disc pl-5">
  <li>Blue bullet</li>
  <li>Blue bullet</li>
</ul>

<!-- Style text selection -->
<p class="selection:bg-blue-200 selection:text-blue-900">
  Select this text to see a blue highlight.
</p>

<!-- Global selection (in CSS) -->
::selection { background: #bfdbfe; color: #1e3a8a; }

<!-- First-line / first-letter -->
<p class="first-letter:text-5xl first-letter:font-bold
          first-letter:float-left first-letter:mr-2
          first-line:uppercase first-line:tracking-wide">
  Drop cap paragraph.
</p>
21

Arbitrary Values & Customization

Arbitrary Values

Square brackets let you use any CSS value without extending the theme — perfect for one-offs. Underscores in values become spaces (so grid-cols-[200px_1fr] becomes '200px 1fr'). Overuse leads to inconsistent design; prefer theme extension for repeated values.

tailwind
<!-- Any CSS value in square brackets -->
<div class="w-[300px] h-[200px] bg-[#1da1f2]">
  Custom sizes and colors
</div>

<p class="text-[13px] leading-[1.6]">
  Custom typography
</p>

<div class="grid-cols-[200px_1fr_100px]">
  Custom grid template (underscores = spaces)
</div>

<div class="top-[117px]">
  Custom positioning
</div>

Arbitrary Properties

[property:value] defines an arbitrary CSS property — useful for properties Tailwind doesn't have utilities for (mask-type, hyphens, etc.). [--var:value] sets a CSS variable you can then reference in arbitrary values like p-[var(--tw)]. Powerful for theming.

tailwind
<!-- Define an arbitrary CSS property -->
<div class="[mask-type:luminance]">
  Sets mask-type: luminance
</div>

<!-- Arbitrary property with Tailwind variable -->
<div class="[--scroll-offset:56px] top-[var(--scroll-offset)]">
  Custom CSS variable
</div>

<!-- CSS variables + arbitrary values are powerful together -->
<div class="[--tw:1rem] p-[var(--tw)]">
  Theme-driven custom value
</div>

Arbitrary Variants

Arbitrary variants extend Tailwind's variant system: min-[1200px]: for custom breakpoints, aria-*: for ARIA states, odd:/even: for striping, has-[:checked]: for relational styling. The has-* variant (a recent CSS feature) is particularly powerful for styling parents based on child state.

tailwind
<!-- Arbitrary media query -->
<div class="min-[1200px]:flex">Custom breakpoint</div>

<!-- ARIA attribute variants -->
<button aria-pressed="true"
        class="aria-pressed:bg-blue-600">
  Toggle styled by ARIA state
</button>

<!-- nth-child -->
<li class="odd:bg-gray-50">Striped table row</li>
<li class="even:bg-white">Striped table row</li>

<!-- has: variant (Tailwind v3.4+) -->
<div class="has-[:checked]:bg-blue-50">
  Highlights when it contains a checked input
</div>

Theme Extension

theme.extend adds to defaults; theme.{key} replaces them. DEFAULT lets you use the base name (bg-brand) plus shades (bg-brand-dark). Add custom spacing, breakpoints, radii, etc. Extending is almost always what you want — replacing the color palette removes Tailwind's defaults.

tailwind
// tailwind.config.js
module.exports = {
  theme: {
    extend: {
      colors: {
        brand: { light: "#5eead4", DEFAULT: "#14b8a6", dark: "#0f766e" },
      },
      spacing: { 18: "4.5rem" },
      borderRadius: { xl: "1rem" },
      screens: { tall: { raw: "(min-height: 800px)" } },
    },
  },
};

<!-- Now you can use: -->
<div class="bg-brand text-brand-light p-18 rounded-xl">
  Custom themed utilities
</div>

Plugins & @apply

Plugins add new utilities or components (forms, typography, aspect-ratio are official ones). @apply lets you inline Tailwind utilities into custom CSS — useful when you have a class you use identically in dozens of places. Don't overuse @apply; the utility-first approach is usually cleaner.

tailwind
// tailwind.config.js — register a plugin
const forms = require("@tailwindcss/forms");
module.exports = { plugins: [forms] };

/* Use @apply to compose utilities into custom CSS */
@layer components {
  .btn-primary {
    @apply bg-blue-600 text-white font-medium py-2 px-4
           rounded-md hover:bg-blue-700 transition-colors;
  }
}

<!-- Then use the custom class -->
<button class="btn-primary">Save</button>
22

Real-World Patterns

Modal / Dialog

Modal anatomy: fixed inset-0 overlay (covers viewport), z-50 (above everything), flex centering for the panel, and the panel itself positioned relative so it sits above the overlay. backdrop-blur adds polish. Always provide a visible close button and ESC-to-close for accessibility.

tailwind
<div class="fixed inset-0 z-50 flex items-center justify-center">
  <!-- Overlay -->
  <div class="absolute inset-0 bg-black/50 backdrop-blur-sm"></div>
  <!-- Panel -->
  <div class="relative bg-white rounded-xl shadow-2xl
              w-full max-w-md mx-4 p-6">
    <h2 class="text-lg font-semibold mb-4">Modal title</h2>
    <p class="text-gray-600">Modal body content.</p>
    <div class="flex justify-end gap-2 mt-6">
      <button class="px-4 py-2 text-gray-600">Cancel</button>
      <button class="px-4 py-2 bg-blue-600 text-white rounded-md">OK</button>
    </div>
  </div>
</div>

Toast / Notification

Toasts are fixed to a corner (bottom-right is conventional), capped width, with a colored left border indicating type (green=success, red=error, yellow=warning, blue=info). Pair with a JS-driven animation (slide-in via translate-x) and auto-dismiss after a few seconds.

tailwind
<div class="fixed bottom-4 right-4 z-50 max-w-sm
            bg-white rounded-lg shadow-xl border-l-4 border-green-500
            flex items-center gap-3 p-4">
  <div class="text-green-500">
    <svg class="w-5 h-5"><!-- check icon --></svg>
  </div>
  <div class="flex-1">
    <p class="font-medium text-gray-900">Saved successfully</p>
    <p class="text-sm text-gray-500">Your changes are live.</p>
  </div>
  <button class="text-gray-400 hover:text-gray-600">×</button>
</div>

Badge & Pill

Badges are inline-flex pills (rounded-full) or labels (rounded). Use bg-{color}-100 + text-{color}-800 for the soft pastel style. Add a dot (w-1.5 h-1.5 rounded-full) for status indicators. Keep text-xs font-medium for the badge text scale.

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

<span class="inline-flex items-center gap-1 px-2 py-0.5
             rounded-full text-xs font-medium
             bg-blue-100 text-blue-800">
  <span class="w-1.5 h-1.5 rounded-full bg-blue-500"></span>
  Online
</span>

<span class="inline-flex items-center px-2 py-0.5
             rounded text-xs font-medium
             bg-red-100 text-red-800">
  Deprecated
</span>

Empty State

Empty states need: an icon in a soft circle, a short headline, supporting text, and a primary CTA. Center everything (text-center mx-auto), use generous py-12 padding, and tone down colors (gray-400/500 text) so the CTA button draws the eye. Don't just show 'No data'.

tailwind
<div class="text-center py-12 px-4">
  <div class="mx-auto w-16 h-16 rounded-full bg-gray-100
              flex items-center justify-center mb-4">
    <svg class="w-8 h-8 text-gray-400"><!-- icon --></svg>
  </div>
  <h3 class="text-lg font-medium text-gray-900">No items yet</h3>
  <p class="mt-1 text-sm text-gray-500">
    Get started by creating your first item.
  </p>
  <button class="mt-4 bg-blue-600 text-white px-4 py-2 rounded-md">
    New item
  </button>
</div>

Loading Skeleton

Skeleton loaders use animate-pulse on a container of gray blocks shaped like the real content. Match the layout and proportions of the loaded state so there's no jarring shift when data arrives. rounded-full + w-10 h-10 mimics an avatar; varying widths (w-3/4, w-1/2) mimic text lines.

tailwind
<div class="animate-pulse 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="space-y-2">
    <div class="h-3 bg-gray-200 rounded"></div>
    <div class="h-3 bg-gray-200 rounded"></div>
  </div>
  <div class="flex gap-4">
    <div class="w-10 h-10 bg-gray-200 rounded-full"></div>
    <div class="flex-1 space-y-2 py-1">
      <div class="h-3 bg-gray-200 rounded"></div>
      <div class="h-3 bg-gray-200 rounded w-5/6"></div>
    </div>
  </div>
</div>

Was this helpful?

Learning path

Learn from scratch

Learn this language from the ground up with structured lessons.