CSS Grid Subgrid: A Practical Guide to Nested Layouts
Before subgrid, nested grid containers started fresh — they had no way to align their internal tracks to the parent grid. CSS Grid Level 2 fixes that. Here's how to use it.

What Is CSS Grid Subgrid?
CSS Grid Level 1 gave us powerful two-dimensional layouts, but it had a fundamental limitation: any grid item that was itself a grid container would define its own independent track sizing. Its children could not reach up and participate in the parent's column or row tracks — they could only see the tracks their direct container defined.
The subgrid keyword, introduced in the CSS Grid Layout Level 2 specification, solves this exactly. When you declare grid-template-columns: subgrid or grid-template-rows: subgrid on a grid item, that item participates in the parent grid's explicit tracks rather than creating new ones. The child element is still a grid container — its descendants can be placed on the grid — but the track definitions are inherited from the ancestor grid.
Think of it as giving nested elements permission to "look up" at the parent grid and say: use those columns, not mine.
Browser Support in 2026
Subgrid is fully production-safe today. All major browsers have shipped it: Chrome 117+, Firefox 71+, and Safari 16+. According to Can I Use, global support sits above 93% across tracked browsers.
You do not need a progressive enhancement fallback for modern projects. Legacy IE and pre-Chromium Edge are not considerations in 2026 — skip the @supports guard unless you have a specific older-browser requirement from your analytics.
The Core Syntax
To use subgrid, the child element must be both a grid item (placed inside a parent grid) and a grid container (have display: grid set on itself). Then you replace its own track definitions with the subgrid keyword:
/* Parent defines the tracks */
.parent {
display: grid;
grid-template-columns: 1fr 2fr 1fr;
gap: 20px;
}
/* Child spans the parent's columns and subgrids them */
.child {
display: grid;
grid-column: 1 / -1; /* span all parent columns */
grid-template-columns: subgrid; /* inherit parent's 3-column track */
}
The child now inherits the three explicit column tracks — including the parent's gap values. You can subgrid rows the same way:
.child {
display: grid;
grid-row: 1 / 4;
grid-template-rows: subgrid; /* inherit parent row tracks */
}
Key rules to keep in mind: (1) the subgrid child must span more than one track along the axis you're subgridding; (2) gap on the child is ignored — it inherits the parent's gap; (3) you can subgrid both axes simultaneously on the same element.
For the full property reference, see the MDN documentation on CSS subgrid.
Practical Example 1 — Form Fields with Aligned Labels
The classic pain point: a multi-row form where each row has a label and an input. You want all labels to align to the same column and all inputs to align to the same column — across rows that are separate grid items. Without subgrid, you'd either flatten the DOM (losing semantic grouping) or fight with fixed widths.
With subgrid, each fieldset row can inherit the parent's two-column track:
/* Parent: two-column label + input layout */
.form {
display: grid;
grid-template-columns: max-content 1fr;
gap: 12px 20px;
}
/* Each row spans both columns and subgrids them */
.field {
display: grid;
grid-column: 1 / -1;
grid-template-columns: subgrid;
}
.field label { grid-column: 1; }
.field input { grid-column: 2; }
The result: every label aligns perfectly regardless of its text length, and every input stretches to fill the same second column. No JavaScript measuring, no fixed widths. The layout is driven purely by CSS Grid track sizing.
This pattern is particularly powerful for design systems where form components need to work inside different grid contexts — the component just subgrids whatever tracks the parent provides.
Practical Example 2 — Card Grids with Internally Aligned Content
Cards in a grid that need aligned internal sections — header, body, footer — are one of the most common layout headaches in frontend development. The old answer was min-height or align-items: stretch combined with flexbox inside each card. These hacks are fragile and require the card to know its own height in advance.
Subgrid solves it cleanly. Define row tracks on the parent grid, have each card span all of them and subgrid its rows:
/* Parent: three implicit row zones per "row" of cards */
.card-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: auto 1fr auto; /* header / body / footer */
gap: 24px;
}
/* Each card spans one column and all three row zones */
.card {
display: grid;
grid-row: span 3;
grid-template-rows: subgrid;
}
.card-header { /* sits in row zone 1 — same height across all cards */ }
.card-body { /* sits in row zone 2 — stretches to fill remaining space */ }
.card-footer { /* sits in row zone 3 — always pinned to the same baseline */ }
Card headers align across the row. Card bodies fill the middle zone. Card footers sit on the same baseline — without a single line of JavaScript and without any card needing to know how tall its siblings are. As Chrome for Developers notes, this is one of the cases where subgrid eliminates a whole category of layout workarounds.
FAQ
Does subgrid work without setting display:grid on the child?
No — for subgrid to work, the child element must itself be a grid container (display: grid or display: inline-grid). The subgrid keyword then replaces its own track definitions with the parent's.
Can I use subgrid for both rows and columns at the same time?
Yes. You can declare both grid-template-columns: subgrid and grid-template-rows: subgrid on the same child element to inherit both axes from the parent grid simultaneously.
What's the difference between subgrid and display:contents?
display: contents removes the element's box entirely, making its children direct grid participants. Subgrid keeps the child's box and layout context intact while sharing the parent's track definitions — giving you more control over spacing, backgrounds, and accessibility semantics.
Practical frontend guides, twice a month.
Short, focused articles on CSS layout, design systems, and frontend patterns. No fluff.
More from the blog

Winter travel: 7 rules for flying somewhere warm without overpaying
Warm sea in winter is not about big budgets — it's about logic: when to fly, where to stay, and what not to overpay for.

Where to find warm sea in February: calm, uncrowded, affordable
February is the ideal month to escape winter — low season crowds, stable weather, often cheaper than December.
Browse all articles
Frontend guides, CSS patterns, design systems, and more.