Overview

Grid lays out two-dimensional structure: rows and columns that line up. Use it for page shells, dashboards, card galleries, and forms where labels and inputs align across rows. For a single row or column, use css-flexbox. The umbrella page is css.

Use grid when alignment must survive across rows

A single axis with items that grow and shrink is flex; anything with both axes locked, or alignment that must hold across rows, is grid. Nest flex inside grid and the reverse as needed; do not force one primitive to do both jobs.

.page { display: grid; grid-template-columns: 240px 1fr; grid-template-rows: auto 1fr auto; min-block-size: 100dvh; }

Size tracks with fr, minmax(), and auto-fill

Prefer intrinsic sizing so the layout absorbs content variance. 1fr shares free space after intrinsic sizes resolve; minmax(min, max) clamps a track; repeat(auto-fill, minmax(16rem, 1fr)) makes a responsive card grid in one line.

.cards { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr)); }

Use auto-fit instead of auto-fill only when surviving items should stretch to fill the last row.

Use minmax(0, 1fr) to stop overflow

1fr is minmax(auto, 1fr), so a track will not shrink below its content’s minimum size. A 200px 1fr grid with a wide child therefore overflows. Use 200px minmax(0, 1fr), or set min-width: 0 on the grid item.

Align nested content with subgrid

grid-template-rows: subgrid makes a nested grid reuse the parent’s tracks, so card titles, bodies, and footers line up across cards regardless of content height. Subgrid has been Baseline widely available since March 2026.

.cards { display: grid; grid-template-columns: repeat(3, 1fr); grid-template-rows: auto 1fr auto; }
.card { display: grid; grid-row: span 3; grid-template-rows: subgrid; }

Name areas and lines

Numbered lines break when a column is added. Name the areas and place items by name; see css-grid-areas.

.page {
  display: grid;
  grid-template-columns: 240px 1fr;
  grid-template-areas: "sidebar header" "sidebar main" "sidebar footer";
}
.main { grid-area: main; }

Keep layout on the container

The container owns tracks and gaps; items own content. Do not put width, margin-left: auto, or flex on items that already sit in tracks. Change grid-template-columns on the container instead.

Use gap, not margins

gap, row-gap, and column-gap are the gutters. Margins on children leak through nested layouts. Tailwind’s gap-4 compiles to the same property (tailwind).

Avoid common pitfalls

  • Items overflowing tracks. Grid items default to min-width: auto; set min-width: 0 on items that should compress.
  • Counting numeric lines. Name lines or areas.
  • Reordering with order, grid-row-start, or areas. Focus and screen-reader order follow the DOM, not the layout; keep the DOM order sensible (accessibility).