Subgrid flipped how I think about components
I used to treat components as little layout fortresses. Every card, form, or section owned its own grid. Nice and isolated. Also: a nightmare when you want things to line up across components.
Subgrid broke that mental model for me. In a good way. It made me think about layout as a shared skeleton that components hook into, instead of each component reinventing the grid internally.
I will skip the theory lecture. This is how I actually use subgrid in production. With cards, forms, and editorial-style pages that used to need ridiculous CSS.
What subgrid actually solves for me
If you know grid, you already know the pain. You have a parent grid, inside it a card component, and inside that card a grid for title, meta, content, actions.
The problem: those inner grids do not know about the outer columns. So nothing lines up once you start repeating the pattern. You get weird off-by-a-few-pixels misalignments. Or you hard code the same grid-template-columns in three places and regret it later.
subgrid fixes that. It lets a child grid inherit the tracks from its parent. No copy-paste. No calc hacks. One source of truth for the layout skeleton.
Technically it is just this:
.parent {
display: grid;
grid-template-columns: 1fr 2fr;
}
.child {
display: grid;
grid-template-columns: subgrid;
}
But the way this changes how you design components is bigger than that tiny line of CSS.
Subgrid status: can you actually ship this?
I use subgrid in production today. No flags. Not on side projects only.
Support right now is good enough for serious use, if you are not building for ancient browsers:
- Firefox: supports subgrid.
- Safari: supports subgrid.
- Chromium: supports subgrid from Chrome 117+ / Edge 117+.
Which means: if you still need IE, you have bigger problems than layout. For my client work, I treat subgrid as safe with a sensible fallback.
My baseline pattern looks like this:
.layout {
display: grid;
grid-template-columns: minmax(0, 1fr);
}
@supports (grid-template-columns: subgrid) {
.layout--inner {
display: grid;
grid-template-columns: subgrid;
}
}
Without support, components just fall back to a simpler single-column layout. Not pretty, but usable. With support, everything snaps into the shared grid.
Case 1: Card layouts that actually align
The first place subgrid clicked for me was a real project with card-heavy pages. Think dashboard tiles, article cards, product cards. Lots of them. All slightly different. All supposed to feel aligned.
The spec was annoying but fair. Titles should align globally. Description text should wrap but still feel ordered. Action buttons should sit on an invisible baseline. Edge-to-edge cards on mobile, 3-up on tablet, 4-up on wide screens.
Here is the basic structure I landed on:
<section class="card-grid">
<article class="card">
<h2 class="card__title">Title</h2>
<p class="card__meta">Meta</p>
<p class="card__body">Content...</p>
<div class="card__actions">...</div>
</article>
</section>
And the grid CSS:
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
gap: 1.5rem;
}
.card {
display: grid;
grid-template-rows: subgrid;
grid-row: span 4;
padding: 1.25rem 1.5rem;
border-radius: 0.75rem;
background: white;
}
.card-grid {
grid-auto-rows: minmax(0, 1fr);
}
That grid-template-rows: subgrid; on .card is the key move. The parent .card-grid owns the row track sizing. Each card just says “inherit the same rows and span four of them”.
Inside, I pin items to rows:
.card__title {
grid-row: 1;
}
.card__meta {
grid-row: 2;
}
.card__body {
grid-row: 3;
}
.card__actions {
grid-row: 4;
align-self: end;
}
Result: All titles line up across cards. All actions sit on the same baseline, even if some cards have two lines of meta and others have five lines of body text. The grid handles the messy middle.
Old me would have faked this with flex plus “push the button to the bottom” hacks or by hard-coding heights and then fighting overflow. Subgrid let me stop guessing and just tell the browser where each part belongs in the global rhythm.
The nice side effect is that I can add variants without breaking alignment. Add a little badge above the title? Give it grid-row: 1 and move the title to grid-row: 2. The tracks remain consistent. No card CSS explosion.
Case 2: Form alignment that does not depend on luck
The second win for subgrid was forms. Multi-column forms are usually fine until you hit long labels, mixed field types, and optional help text. Then everything drifts. Little misalignments stack up and the whole form feels amateur.
I built a pretty complex signup and onboarding flow for a client. They wanted labels, inputs, captions, and validation messages to line up like a design system brochure. Also: the same form layout on several pages, with different fields in different orders.
I used a parent grid for the entire form, then used subgrid for the individual form rows. Structure first:
<form class="form">
<div class="form__row">
<label class="form__label" for="name">Full name</label>
<div class="form__field">
<input id="name" />
<p class="form__hint">As on your ID.</p>
</div>
</div>
<div class="form__row">
<label class="form__label" for="email">Email</label>
<div class="form__field">
<input id="email" />
<p class="form__error">Please enter a valid email.</p>
</div>
</div>
</form>
And the grid:
.form {
display: grid;
grid-template-columns: minmax(0, 12rem) minmax(0, 1.8fr);
column-gap: 1.5rem;
row-gap: 1rem;
}
.form__row {
display: grid;
grid-template-columns: subgrid;
grid-column: 1 / -1;
}
.form__label {
grid-column: 1;
align-self: start;
}
.form__field {
grid-column: 2;
display: grid;
grid-template-rows: auto auto;
}
.form__hint,
.form__error {
font-size: 0.85rem;
color: #666;
}
.form__error {
color: #d33;
}
The parent .form decides the label column and the field column once. Every .form__row inherits that layout with grid-template-columns: subgrid;. Each label and field uses the same tracks, without me repeating the column definition in every row class.
The interesting part is when you start changing layouts responsively. On smaller screens, I collapse the grid:
@media (max-width: 40rem) {
.form {
grid-template-columns: minmax(0, 1fr);
}
.form__row {
grid-template-columns: subgrid;
}
.form__label,
.form__field {
grid-column: 1;
}
}
Still only one place where I touch the columns. The subgrid rows just follow. Labels and fields stack cleanly without extra wrappers or layout variants.
What I like about this pattern is that it keeps the HTML boring. No extra containers for each breakpoint. Semantically, these are rows in a form. Visually, I just change the rules for how the rows inherit tracks from their parent.
Case 3: Editorial grids that stop fighting the content
The last example is a more editorial layout. Think marketing pages with copy, images, pull quotes, and “by the way” boxes that break out of the normal flow.
I used subgrid on a long article template for my own site. The design goal was simple: text wraps within a comfortable measure, but supporting content like images, notes, and code blocks can snap to a wider grid.
The HTML is roughly:
<main class="article">
<header class="article__header">...</header>
<div class="article__body">
<section class="section">
<h2 class="section__title">Heading</h2>
<div class="section__content">
<p>Text...</p>
<figure class="figure figure--wide">...</figure>
<aside class="callout">...</aside>
</div>
</section>
</div>
</main>
The layout grid:
.article {
display: grid;
grid-template-columns:
minmax(1rem, 1fr)
minmax(0, 7ch)
minmax(0, 60ch)
minmax(0, 7ch)
minmax(1rem, 1fr);
}
.article__body {
display: grid;
grid-column: 1 / -1;
grid-template-columns: subgrid;
}
.section {
display: grid;
grid-template-columns: subgrid;
grid-column: 2 / 5;
}
.section__title {
grid-column: 3;
}
.section__content {
grid-column: 3;
}
.figure--wide {
grid-column: 2 / 4;
}
.callout {
grid-column: 4;
}
The top level .article owns the full editorial grid. Two gutter columns, one main text column, and optional side columns for notes or pull quotes. Then both .article__body and each .section use grid-template-columns: subgrid; so everything shares the same tracks.
Inside a section, I can place content relative to that skeleton. Normal paragraphs sit in column 3. Wide figures span columns 2 to 4. Callouts can live in column 4, which feels like a margin note on desktop and drops below on narrow screens.
The important bit: I never duplicate the column setup. There is only one opinionated grid. Components just snap into it.
When I first sketched this layout, I assumed I would need separate wrappers for wide content sections. Something like .section--wide with its own grid. Subgrid made that unnecessary. The section just declares which columns it wants to occupy.
This changed how I think about “page builders” too. If you define the editorial grid once and then let blocks subgrid into it, you get a lot of freedom without layout entropy.
How subgrid changes my component design
Using subgrid in real projects forced a few mindset shifts.
I design the page grid first, not the component
Before, I would jump into a Card component and ask “what is the best layout for this card?”. Now I start higher up. What is the site-wide rhythm? How many columns should the main content area have? Where do I want baselines to line up?
Once that skeleton exists, components are mostly slotting content into shared tracks. Cards, form rows, feature blocks, all inherit from the same system. It feels more like typesetting and less like random div Tetris.
I treat spacing as part of the grid
Instead of throwing margin-bottom on everything, I lean harder on grid gaps and shared row tracks. In the card example, I barely use margins inside the card. The parent grid's row-gap and grid-auto-rows create the rhythm.
That gives me one knob to turn when design changes come in. If we tighten vertical spacing, I tweak a gap, not fifteen margins across three components.
I accept that not everything should be a subgrid
Subgrid is powerful but not universal. I still use local grids inside components when the layout really is self-contained and does not need to sync with siblings.
For example, inside .form__field I used a normal grid for input + help text. Subgrid there would just add cognitive overhead, because that tiny layout is not supposed to align with anything outside.
My rough rule: if the thing is meant to visually sync with siblings or with a site-wide pattern, consider subgrid. Otherwise use a regular grid or flex.
Practical gotchas I actually hit
A few things bit me early on. You can avoid them.
- You need tracks on the parent. Subgrid cannot invent tracks. If the parent has
grid-template-rowsorgrid-template-columnsnot defined, subgrid has nothing to inherit. Set explicit tracks or usegrid-auto-rows. - Row vs column subgrid are separate. You can do
grid-template-rows: subgrid;without subgridding columns, and vice versa. I often subgrid rows in cards and columns in forms. - Auto-placement can surprise you. When you mix explicit
grid-rowandgrid-columnwith auto-placed items inside a subgrid, walk through what the browser will do. I ended up addinggrid-auto-flow: rowin a few parents to keep things predictable. - Fallbacks matter if you have strict design QA. Using
@supportsto toggle subgrid on and off works, but make sure non-subgrid layouts do not look broken, just simpler.
Why I think subgrid is worth building around
After a few projects with subgrid, I do not reach for it because it is shiny. I reach for it because it reduces layout duplication and makes complex pages easier to reason about.
Cards, forms, and editorial pages used to be the places I expected layout bugs to hide. Now they are the places where the CSS actually feels calm. One grid to define the structure. Components that opt into that structure explicitly.
If you have a project where alignment really matters, pick one layout and ship it with subgrid. Start with either cards or forms. Do it on a page that you actually care about, not a CodePen toy. The limitations will show up quickly, but so will the mental shift.
For me, that shift was simple. Components are not little layout islands anymore. They are citizens of a shared grid.
Once you build that way for a bit, it is hard to go back.
Subscribe to my newsletter to get the latest updates and news
Member discussion