CSS Grid in Next.js: Complete Guide with Responsive Layouts & Examples

Cover Image for CSS Grid in Next.js: Complete Guide with Responsive Layouts & Examples
toofancoder
toofancoder

CSS Grid in Next.js

CSS Grid is one of the most powerful layout systems in modern web development. It lets you build two-dimensional layouts — controlling both rows and columns — with very little code. When combined with Next.js, you can create responsive, production-ready page layouts fast.

In this guide, we'll cover:

  1. CSS Grid basics — the properties you'll actually use
  2. Responsive card grid — auto-fill, auto-fit, minmax
  3. Dashboard layout — named grid areas (sidebar + header + content)
  4. Mobile-first design — breakpoints done right
  5. CSS Grid vs Flexbox — when to use which

Let's build.


1. CSS Grid Basics

Before jumping to Next.js, here's a quick refresher on the core CSS Grid properties:

.grid-container {
  display: grid;

  /* Define columns: 3 equal columns */
  grid-template-columns: repeat(3, 1fr);

  /* Define rows: auto height */
  grid-template-rows: auto;

  /* Gap between cells */
  gap: 16px;
}

Key properties to know:

  • grid-template-columns — defines how many columns and their widths
  • grid-template-rows — defines row heights
  • gap (or column-gap / row-gap) — spacing between cells
  • grid-column: span 2 — makes an item span 2 columns
  • grid-area — assigns an item to a named area

2. Responsive Card Grid in Next.js

The most common use case for CSS Grid in Next.js is a responsive card grid — a layout that shows 3 cards per row on desktop, 2 on tablet, and 1 on mobile.

The component

Create components/CardGrid.jsx:

// components/CardGrid.jsx

const cards = [
  { id: 1, title: 'Getting Started', description: 'Learn the basics of Next.js and CSS Grid.' },
  { id: 2, title: 'Routing', description: 'How the App Router and file-based routing works.' },
  { id: 3, title: 'Data Fetching', description: 'Server components, fetch, and caching strategies.' },
  { id: 4, title: 'Styling', description: 'CSS Modules, Tailwind, and global styles in Next.js.' },
  { id: 5, title: 'Deployment', description: 'Deploy your Next.js app to Vercel in minutes.' },
  { id: 6, title: 'Optimizations', description: 'Images, fonts, and performance best practices.' },
];

export default function CardGrid() {
  return (
    <div className="card-grid">
      {cards.map((card) => (
        <div key={card.id} className="card">
          <h3>{card.title}</h3>
          <p>{card.description}</p>
        </div>
      ))}
    </div>
  );
}

The CSS

/* styles/CardGrid.module.css */

.card-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
  padding: 24px;
}

.card {
  background: #ffffff;
  border: 1px solid #e5e7eb;
  border-radius: 12px;
  padding: 24px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
  transition: box-shadow 0.2s ease;
}

.card:hover {
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
}

.card h3 {
  margin: 0 0 8px;
  font-size: 1.1rem;
  font-weight: 600;
  color: #111827;
}

.card p {
  margin: 0;
  font-size: 0.9rem;
  color: #6b7280;
  line-height: 1.5;
}

/* Tablet: 2 columns */
@media (max-width: 1024px) {
  .card-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* Mobile: 1 column */
@media (max-width: 640px) {
  .card-grid {
    grid-template-columns: 1fr;
    padding: 16px;
  }
}

Result

Responsive card grid showing 3 columns on desktop with cards spanning correctly

The same grid adapts automatically across screen sizes:

Responsive CSS Grid across desktop, tablet, and mobile breakpoints

Auto-fill vs Auto-fit (the smarter way)

Instead of manually defining breakpoints, you can let the browser figure out the column count:

.card-grid {
  display: grid;

  /* Browser creates as many columns as fit, each min 280px wide */
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));

  gap: 24px;
}
  • auto-fill — creates as many columns as possible, even if empty
  • auto-fit — collapses empty columns, stretching filled ones
  • minmax(280px, 1fr) — each column is at least 280px, at most 1 fraction of space

This single line replaces all your media queries for a basic card grid.


3. A Card with Column Span

Sometimes you want one card to be wider — like a featured item. Use grid-column: span 2:

export default function CardGridWithFeatured() {
  return (
    <div className="card-grid">
      {/* This card takes up 2 columns */}
      <div className="card card--featured">
        <h3>Featured: New in Next.js 15</h3>
        <p>Turbopack is now stable, React 19 support, and improved caching.</p>
      </div>

      <div className="card"><h3>Card 2</h3><p>Regular card.</p></div>
      <div className="card"><h3>Card 3</h3><p>Regular card.</p></div>
      <div className="card"><h3>Card 4</h3><p>Regular card.</p></div>
    </div>
  );
}
.card--featured {
  grid-column: span 2;
  background: linear-gradient(135deg, #6366f1, #8b5cf6);
  color: white;
  border: none;
}

.card--featured h3,
.card--featured p {
  color: white;
}

/* Don't span on mobile — it breaks the layout */
@media (max-width: 640px) {
  .card--featured {
    grid-column: span 1;
  }
}

4. Dashboard Layout with Named Grid Areas

For a more complex layout — like a dashboard with a sidebar, header, stats, and content — CSS Grid's grid-template-areas is the cleanest approach.

Dashboard layout built with CSS Grid named areas: sidebar, header, stats, chart, panel

The layout

// app/dashboard/page.jsx

import Sidebar from '@/components/Sidebar';
import Header from '@/components/Header';
import StatsRow from '@/components/StatsRow';
import Chart from '@/components/Chart';
import ActivityPanel from '@/components/ActivityPanel';

export default function DashboardPage() {
  return (
    <div className="dashboard">
      <aside className="dashboard__sidebar"><Sidebar /></aside>
      <header className="dashboard__header"><Header /></header>
      <section className="dashboard__stats"><StatsRow /></section>
      <main className="dashboard__chart"><Chart /></main>
      <aside className="dashboard__panel"><ActivityPanel /></aside>
    </div>
  );
}

The CSS

.dashboard {
  display: grid;
  height: 100vh;
  grid-template-columns: 260px 1fr 320px;
  grid-template-rows: 64px auto 1fr;
  grid-template-areas:
    "sidebar header  header"
    "sidebar stats   stats"
    "sidebar chart   panel";
  gap: 16px;
  background: #f1f5f9;
  padding: 16px;
}

.dashboard__sidebar { grid-area: sidebar; }
.dashboard__header  { grid-area: header; }
.dashboard__stats   { grid-area: stats; }
.dashboard__chart   { grid-area: chart; }
.dashboard__panel   { grid-area: panel; }

/* Collapse to single column on tablet */
@media (max-width: 1024px) {
  .dashboard {
    grid-template-columns: 1fr;
    grid-template-rows: auto;
    grid-template-areas:
      "header"
      "stats"
      "chart"
      "panel";
    height: auto;
  }

  .dashboard__sidebar {
    display: none; /* or use a hamburger menu */
  }
}

The magic here is grid-template-areas — it reads exactly like the visual layout. Each string is a row, each word is a column area.


5. CSS Grid in Next.js with Tailwind

If your Next.js project uses Tailwind CSS, you get utility classes that map directly to CSS Grid:

export default function TailwindCardGrid({ items }) {
  return (
    <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6 p-6">
      {items.map((item) => (
        <div
          key={item.id}
          className="bg-white rounded-xl border border-gray-200 p-6 shadow-sm hover:shadow-md transition-shadow"
        >
          <h3 className="text-lg font-semibold text-gray-900 mb-2">{item.title}</h3>
          <p className="text-sm text-gray-500">{item.description}</p>
        </div>
      ))}
    </div>
  );
}

Key Tailwind grid classes:

Class CSS equivalent
grid display: grid
grid-cols-3 grid-template-columns: repeat(3, 1fr)
sm:grid-cols-2 2 columns on small screens
lg:grid-cols-4 4 columns on large screens
gap-6 gap: 1.5rem
col-span-2 grid-column: span 2

6. CSS Grid vs Flexbox — When to Use Which

A common question when building layouts in Next.js is whether to use CSS Grid or Flexbox. Here's a simple rule:

Scenario Use
Two-dimensional layout (rows AND columns) CSS Grid
One-dimensional layout (row OR column) Flexbox
Card grid, dashboard, page layout CSS Grid
Navigation bar, button group, icon + text Flexbox
Unknown number of items that should wrap CSS Grid with auto-fill
Items that should push to the edges Flexbox with justify-content: space-between

In practice, you'll use both — Flexbox inside cards, CSS Grid for the card container.


Conclusion

CSS Grid is one of the most underused tools in Next.js development. Here's what we covered:

  • Responsive card grid with repeat(auto-fill, minmax()) — one line replaces all breakpoints
  • Column spanning with grid-column: span 2 for featured items
  • Dashboard layouts with grid-template-areas for readable, visual CSS
  • Tailwind integration with grid utility classes
  • Grid vs Flexbox — choosing the right tool for each job

CSS Grid works out of the box in Next.js — no library needed. Start with the card grid pattern, and once you're comfortable, move on to named grid areas for complex page layouts.

Happy coding! 🚀