CSS Grid Layouts with Tailwind CSS
Build powerful grid layouts using Tailwind's grid utilities, auto-fill, auto-fit, spanning, subgrid patterns, and real-world layout examples.
What you'll learn
- ✓How Tailwind grid utilities map to CSS Grid properties
- ✓Building responsive grids with auto-fill and auto-fit
- ✓Spanning rows and columns for complex layouts
- ✓Using subgrid for aligned nested grids
- ✓Real-world patterns: dashboards, galleries, and Bento grids
Prerequisites
- •Basic Tailwind CSS knowledge
- •Understanding of CSS Grid fundamentals
CSS Grid is the most powerful layout system in CSS, and Tailwind gives you utility classes for every grid property. This article covers the full range: from simple column grids to complex dashboard layouts with spanning, auto-placement, and subgrid.
Grid Fundamentals in Tailwind
The core classes you need:
Tailwind Class | CSS Property
-----------------------|---------------------------
grid | display: grid
grid-cols-3 | grid-template-columns: repeat(3, minmax(0, 1fr))
grid-rows-2 | grid-template-rows: repeat(2, minmax(0, 1fr))
gap-4 | gap: 1rem
col-span-2 | grid-column: span 2 / span 2
row-span-2 | grid-row: span 2 / span 2
col-start-2 | grid-column-start: 2
row-start-1 | grid-row-start: 1 A basic three-column grid:
<div class="grid grid-cols-3 gap-4">
<div class="bg-blue-100 p-4 rounded">Item 1</div>
<div class="bg-blue-100 p-4 rounded">Item 2</div>
<div class="bg-blue-100 p-4 rounded">Item 3</div>
<div class="bg-blue-100 p-4 rounded">Item 4</div>
<div class="bg-blue-100 p-4 rounded">Item 5</div>
<div class="bg-blue-100 p-4 rounded">Item 6</div>
</div>
Six items flow into two rows of three columns automatically. CSS Grid handles the placement.
Responsive Column Counts
The most common pattern is changing column counts at breakpoints:
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
<div class="rounded-lg border p-6">Card 1</div>
<div class="rounded-lg border p-6">Card 2</div>
<div class="rounded-lg border p-6">Card 3</div>
<div class="rounded-lg border p-6">Card 4</div>
<div class="rounded-lg border p-6">Card 5</div>
<div class="rounded-lg border p-6">Card 6</div>
<div class="rounded-lg border p-6">Card 7</div>
<div class="rounded-lg border p-6">Card 8</div>
</div>
Mobile shows one column, small screens show two, laptops show three, and desktops show four.
Auto-Fill and Auto-Fit
Instead of setting explicit column counts at breakpoints, let the grid figure it out. Use arbitrary values:
<!-- auto-fill: items are at least 250px, grid creates as many columns as fit -->
<div class="grid grid-cols-[repeat(auto-fill,minmax(250px,1fr))] gap-6">
<div class="rounded-lg border bg-white p-6 shadow-sm">Product 1</div>
<div class="rounded-lg border bg-white p-6 shadow-sm">Product 2</div>
<div class="rounded-lg border bg-white p-6 shadow-sm">Product 3</div>
<div class="rounded-lg border bg-white p-6 shadow-sm">Product 4</div>
<div class="rounded-lg border bg-white p-6 shadow-sm">Product 5</div>
</div>
Container: 1200px wide | Min item: 250px
auto-fill with 3 items:
[ Item 1 ] [ Item 2 ] [ Item 3 ] [ empty ]
-> Empty tracks preserved, items stay 250-300px
auto-fit with 3 items:
[ Item 1 ] [ Item 2 ] [ Item 3 ]
-> Empty tracks collapse, items stretch to fill Use auto-fill when you want consistent item sizes. Use auto-fit when you want items to stretch and fill the container.
Spanning Columns and Rows
Make items take up multiple cells:
<div class="grid grid-cols-4 gap-4">
<!-- Featured item spans 2 columns -->
<div class="col-span-2 bg-indigo-100 p-6 rounded-lg">
<h2 class="text-lg font-bold">Featured Article</h2>
<p class="text-gray-600 mt-2">This spans two columns for emphasis.</p>
</div>
<div class="bg-gray-100 p-6 rounded-lg">Regular</div>
<div class="bg-gray-100 p-6 rounded-lg">Regular</div>
<!-- Full-width banner spans all 4 columns -->
<div class="col-span-4 bg-yellow-50 p-6 rounded-lg text-center">
Full-width banner across all columns
</div>
</div>
Span both directions for a feature card:
<div class="grid grid-cols-3 grid-rows-3 gap-4 h-[500px]">
<!-- Large feature: 2 columns, 2 rows -->
<div class="col-span-2 row-span-2 bg-blue-600 text-white p-8 rounded-xl flex items-end">
<div>
<h2 class="text-2xl font-bold">Main Feature</h2>
<p class="mt-2 text-blue-100">Spanning 2 columns and 2 rows.</p>
</div>
</div>
<div class="bg-green-100 p-4 rounded-xl">Small 1</div>
<div class="bg-green-100 p-4 rounded-xl">Small 2</div>
<div class="bg-purple-100 p-4 rounded-xl">Small 3</div>
<div class="bg-purple-100 p-4 rounded-xl">Small 4</div>
<div class="bg-purple-100 p-4 rounded-xl">Small 5</div>
</div>
Explicit Placement
Use col-start-* and row-start-* to place items at specific grid positions:
<div class="grid grid-cols-4 grid-rows-3 gap-4">
<!-- Place item at column 3, row 1 -->
<div class="col-start-3 row-start-1 bg-red-100 p-4 rounded">
Placed at col 3, row 1
</div>
<!-- Place item spanning from column 1 to column 3 -->
<div class="col-start-1 col-end-3 row-start-2 bg-blue-100 p-4 rounded">
Columns 1-2, row 2
</div>
</div>
Subgrid
Subgrid lets a nested grid inherit its parent’s track sizes, so items in different grid children align perfectly. Tailwind v3.4+ supports this:
<div class="grid grid-cols-3 gap-6">
<!-- Each card uses subgrid to align title, description, and CTA -->
<div class="grid grid-rows-subgrid row-span-3 gap-2 rounded-lg border p-6">
<h3 class="text-lg font-bold">Starter Plan</h3>
<p class="text-gray-600">Perfect for individuals getting started.</p>
<button class="self-end rounded bg-blue-600 px-4 py-2 text-white">Choose</button>
</div>
<div class="grid grid-rows-subgrid row-span-3 gap-2 rounded-lg border p-6">
<h3 class="text-lg font-bold">Pro Plan</h3>
<p class="text-gray-600">For growing teams that need more power and integrations.</p>
<button class="self-end rounded bg-blue-600 px-4 py-2 text-white">Choose</button>
</div>
<div class="grid grid-rows-subgrid row-span-3 gap-2 rounded-lg border p-6">
<h3 class="text-lg font-bold">Enterprise</h3>
<p class="text-gray-600">Custom solutions for large organizations with compliance needs.</p>
<button class="self-end rounded bg-blue-600 px-4 py-2 text-white">Choose</button>
</div>
</div>
Without subgrid, the “Choose” button in each card would sit at a different vertical position depending on how long the description is. With grid-rows-subgrid, all three cards share the same row heights, and the buttons align perfectly.
Real-World Pattern: Bento Grid
The trendy “Bento box” layout seen on Apple’s marketing pages:
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 p-4">
<!-- Large hero block -->
<div class="col-span-2 row-span-2 rounded-2xl bg-gradient-to-br from-purple-600 to-blue-500 p-8 text-white flex flex-col justify-end min-h-[300px]">
<h2 class="text-3xl font-bold">Ship Faster</h2>
<p class="mt-2 text-purple-100">Deploy in seconds, not hours.</p>
</div>
<!-- Stats blocks -->
<div class="rounded-2xl bg-gray-100 p-6 flex flex-col justify-center">
<p class="text-4xl font-bold">99.9%</p>
<p class="text-sm text-gray-500 mt-1">Uptime SLA</p>
</div>
<div class="rounded-2xl bg-gray-100 p-6 flex flex-col justify-center">
<p class="text-4xl font-bold">50ms</p>
<p class="text-sm text-gray-500 mt-1">Avg response</p>
</div>
<!-- Wide feature -->
<div class="col-span-2 rounded-2xl bg-green-50 p-6">
<h3 class="font-semibold">Built-in Analytics</h3>
<p class="text-gray-600 mt-1">Track every metric that matters.</p>
</div>
<!-- Bottom row -->
<div class="rounded-2xl bg-orange-50 p-6">
<h3 class="font-semibold">API First</h3>
<p class="text-sm text-gray-600 mt-1">REST and GraphQL.</p>
</div>
<div class="rounded-2xl bg-blue-50 p-6">
<h3 class="font-semibold">Edge Ready</h3>
<p class="text-sm text-gray-600 mt-1">Deploy to 300+ locations.</p>
</div>
</div>
Real-World Pattern: Dashboard Grid
A dashboard with a sidebar, header, and content area:
<div class="grid min-h-screen grid-cols-[250px_1fr] grid-rows-[64px_1fr]">
<!-- Header spanning full width -->
<header class="col-span-2 flex items-center justify-between border-b bg-white px-6">
<h1 class="text-lg font-bold">Dashboard</h1>
<span class="text-sm text-gray-500">Welcome back</span>
</header>
<!-- Sidebar -->
<aside class="border-r bg-gray-50 p-4">
<nav class="space-y-2">
<a href="#" class="block rounded px-3 py-2 text-sm font-medium bg-blue-50 text-blue-700">Overview</a>
<a href="#" class="block rounded px-3 py-2 text-sm text-gray-700 hover:bg-gray-100">Analytics</a>
<a href="#" class="block rounded px-3 py-2 text-sm text-gray-700 hover:bg-gray-100">Users</a>
<a href="#" class="block rounded px-3 py-2 text-sm text-gray-700 hover:bg-gray-100">Settings</a>
</nav>
</aside>
<!-- Main content -->
<main class="overflow-auto bg-gray-100 p-6">
<div class="grid grid-cols-1 gap-6 sm:grid-cols-2 xl:grid-cols-3">
<div class="rounded-lg bg-white p-6 shadow-sm">
<p class="text-sm text-gray-500">Total Revenue</p>
<p class="text-2xl font-bold mt-1">$48,200</p>
</div>
<div class="rounded-lg bg-white p-6 shadow-sm">
<p class="text-sm text-gray-500">Active Users</p>
<p class="text-2xl font-bold mt-1">2,340</p>
</div>
<div class="rounded-lg bg-white p-6 shadow-sm">
<p class="text-sm text-gray-500">Conversion Rate</p>
<p class="text-2xl font-bold mt-1">4.6%</p>
</div>
</div>
</main>
</div>
For mobile, you would typically hide the sidebar and use grid-cols-1:
<div class="grid min-h-screen grid-cols-1 grid-rows-[64px_1fr] lg:grid-cols-[250px_1fr]">
<!-- Sidebar hidden on mobile -->
<aside class="hidden lg:block border-r bg-gray-50 p-4">
<!-- nav links -->
</aside>
<!-- ... -->
</div>
Gap Utilities
Control spacing between grid items:
<!-- Uniform gap -->
<div class="grid grid-cols-3 gap-4">...</div>
<!-- Different horizontal and vertical gaps -->
<div class="grid grid-cols-3 gap-x-8 gap-y-4">...</div>
<!-- Responsive gaps -->
<div class="grid grid-cols-3 gap-4 md:gap-6 lg:gap-8">...</div>
Alignment and Justification
Control how items sit within their grid cells:
<!-- Center all items in their cells -->
<div class="grid grid-cols-3 gap-4 place-items-center h-64">
<div class="bg-blue-200 p-4 rounded">Centered</div>
<div class="bg-blue-200 p-4 rounded">Centered</div>
<div class="bg-blue-200 p-4 rounded">Centered</div>
</div>
<!-- Stretch items to fill cells (default) -->
<div class="grid grid-cols-3 gap-4 items-stretch">...</div>
<!-- Align items to the bottom of their cells -->
<div class="grid grid-cols-3 gap-4 items-end h-64">...</div>
<!-- Per-item alignment -->
<div class="grid grid-cols-3 gap-4 h-64">
<div class="self-start bg-red-100 p-4">Top</div>
<div class="self-center bg-green-100 p-4">Middle</div>
<div class="self-end bg-blue-100 p-4">Bottom</div>
</div>
Common Pitfalls
Using grid-cols-12 for everything. This is a Bootstrap habit. CSS Grid does not need a 12-column base. Use the number of columns you actually want.
Forgetting minmax(0, 1fr). Tailwind’s grid-cols-* uses minmax(0, 1fr) by default, which prevents content from overflowing the grid. If you use arbitrary values, remember to include it.
Overflows from long words. Grid items will not shrink below their content size by default. Add min-w-0 or overflow-hidden to grid children that contain long text or images.
Mixing flexbox and grid. Use grid for two-dimensional layouts (rows and columns). Use flexbox for one-dimensional layouts (a row or a column). Do not force one to do the other’s job.
Wrap-Up
Tailwind’s grid utilities cover the full CSS Grid spec: explicit and implicit tracks, spanning, placement, alignment, auto-fill/auto-fit, and subgrid. Start with grid grid-cols-N gap-N, make it responsive with breakpoint prefixes, and reach for auto-fill when you want the grid to adapt without breakpoints. Use subgrid to align content across sibling grid children, and build complex layouts by combining spanning with explicit placement.
Related articles
- Tailwind Responsive Design Patterns with Tailwind CSS
Master mobile-first breakpoints, container queries, responsive grids, and real-world layout patterns using Tailwind CSS utilities.
- Tailwind Tailwind Layout: Flex, Grid, Spacing, Sizing
A practical tour of Tailwind's layout utilities — flex and grid, alignment, gap, padding and margin, width and height, and responsive prefixes — built around a real card layout example.
- HTML & CSS CSS Grid vs Flexbox: When to Use Each (with Examples)
Stop flipping a coin between Grid and Flexbox. Learn the mental model that picks the right layout tool every time, with practical CSS examples.
- HTML & CSS CSS Subgrid Tutorial
Use CSS subgrid to align nested elements with their parent grid, perfect for card layouts, forms, and complex content where rows and columns must line up across components.