Flexbox vs CSS Grid: Choosing by Axis Count, Not by Page vs Component
Replaces the 'grid for page, flexbox for component' rule with the actual decision criterion: one-axis distribution versus two-axis row-and-column alignment.
You are staring at a form with three fields and a submit button. The labels must line up with the inputs, and the submit button must sit flush with the input edges, not the label edges. You reach for flexbox because it worked on the last card row. It works, sort of, until the validation message under the second input runs twenty pixels taller than the one under the first. Suddenly the third input is no longer where your eye expects it. That moment is the one-axis two-axis layout decision. It is not about page versus component. It is about whether you need to align items across rows and columns simultaneously, or whether you are distributing space along a single axis. The old rule that grid is for pages and flexbox is for components was written before subgrid shipped, and it has been quietly wrong since September 2023.
The misleading rule came from the 2014-era CSS layout conversation, when grid was a spec and flexbox was the new thing everyone was learning. It made sense then: pages have rows and columns, components have a stack or a row of items. But that rule conflated the size of the layout with the number of axes it needs. A page can be a single column of stacked sections. That is one-dimensional and flexbox handles it fine. A component can be a table of form fields. That is two-dimensional, and grid is the only tool that aligns the fields correctly. The real question is not how large the thing is. It is whether your layout has items that must share alignment across the horizontal and vertical axes at the same time. If yes, you need grid. If no, flexbox is the lighter tool.
The Failure Case That Exposes The Difference
Build a component with three rows of a form: label, input, and a small helper text under each input. In flexbox, set the container to flex-direction: column. Each row is its own flex item. That works until the helper text under the second input wraps to two lines. The third input moves down, but the first and second inputs stay where they were. Each row is independent. The inputs no longer align across rows. You try align-items: stretch, but that only affects the cross axis of the whole flex container, not the alignment of items across separate flex lines. Flexbox has no concept of a column track that persists across rows. That is the one-dimensional limit.
The Same Component In Grid
The same component in grid fixes it because grid has explicit tracks. Define three column tracks for label, input, and helper, and three row tracks, one per form row. The grid items sit in the same column for all three rows, so the inputs align even when the helper text lengths differ. Here is the complete sample:
.form-grid {
display: grid;
grid-template-columns: 8rem 1fr;
grid-template-rows: auto auto auto;
gap: 0.5rem 1rem;
align-items: start;
}
.form-grid label {
grid-column: 1;
}
.form-grid input {
grid-column: 2;
width: 100%;
}
.form-grid .helper {
grid-column: 2;
font-size: 0.875rem;
color: #666;
min-height: 1rem;
}
That is the two-dimensional answer. The labels sit in column 1, the inputs and helpers sit in column 2, and the gap property handles the spacing between rows and columns in one declaration. No floats, no negative margins, no clearing hacks.
Why Subgrid Changes The Decision
Now the subgrid part, which makes grid correct for many component-internal alignments that used to force flexbox. Subgrid lets a child grid inherit the track definitions of its parent grid. Items inside the child align with items in the parent without you re-declaring the track sizes. This matters for components with nested groups, like a card with a header row and a list of rows inside it, where the header column widths must match the list column widths. Before this feature shipped, you had two options: use flexbox and give up on cross-row alignment, or hard-code the same track sizes in both grids and hope they match. Subgrid removes the guesswork.
Here is a component that works in flexbox but breaks when items must align across rows, and the grid with subgrid that fixes it. The flexbox version uses two separate flex containers, so the columns do not align. The grid version uses one parent grid and a subgrid child, so they do. The sample runs in any browser that supports this feature, which is all major engines as of the Baseline 2023 update.
/* The flexbox version: columns do not align across rows */
.flex-header {
display: flex;
gap: 1rem;
}
.flex-list {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.flex-list > div {
display: flex;
gap: 1rem;
}
<div class="flex-header">
<span>Name</span><span>Price</span>
</div>
<div class="flex-list">
<div><span>Item</span><span>$10</span></div>
<div><span>Longer item name</span><span>$20</span></div>
</div>
The header column widths are set by the header content, and the list column widths are set by the list content. They do not match. The fix is grid with subgrid:
.grid-parent {
display: grid;
grid-template-columns: 1fr auto;
gap: 0.5rem 1rem;
}
.grid-parent .header {
display: grid;
grid-column: 1 / -1;
grid-template-columns: subgrid;
}
.grid-parent .list {
display: grid;
grid-column: 1 / -1;
grid-template-columns: subgrid;
row-gap: 0.5rem;
}
The parent defines the two column tracks once. The header and the list both inherit those tracks via subgrid, so every row in the list aligns with the header. This is the case where grid is the correct choice for a component, and flexbox is not. The axis count decides it, not the size of the thing.
Flexbox vs CSS Grid One-Axis Two-Axis Layout Decision: The Criterion in Practice
The criterion is straightforward. If you need to control alignment along both the row axis and the column axis at the same time, use grid. If you only need to distribute items along a single axis, either row or column, use flexbox. Flexbox is one-dimensional. It lays out items along the main axis and handles the cross axis only as a secondary alignment, not as a track system. Grid is two-dimensional. It defines explicit row and column tracks that items are placed into, and those tracks persist across the whole grid container. The flex-direction property in flexbox picks the main axis, and flex-wrap creates new lines. Those lines do not share alignment with each other. Grid's grid-template-columns and grid-template-rows define the tracks up front, so every item in a column is aligned to that column's track, regardless of where it sits in the row order.
CSS Grid Subgrid Component Alignment: When Grid Beats Flexbox Inside a Component
Subgrid is the feature that collapses the old page-versus-component rule. It landed in all major browsers, with Baseline status newly available since September 2023, and it lets a grid item become a grid container that inherits the parent's track definitions. A nested component can align its internal rows and columns with the parent grid without you duplicating track sizes. For a card in a dashboard, where the header, body, and footer each need the same column widths, this feature is the difference between a brittle hard-coded layout and one that adapts to content. Flexbox has no equivalent because it has no track concept. When you see a component with multiple rows and columns that must share alignment, grid with `subgrid` is the answer. Flexbox is the wrong tool, despite the component being small.
Flexbox Grid Layout Decision Criteria: The Checklist That Ends The Guesswork
Use this checklist. If you need to align items across both rows and columns, choose grid. If you need to distribute items along one axis and the cross-axis alignment is secondary, choose flexbox. If you have a component with nested groups that must share column widths, choose grid with subgrid. If you have a single row of navigation links or a toolbar, flexbox is the lighter choice. If you have a form with labels and inputs in multiple rows, grid is correct because the label column must align across all rows. If you have a card grid where each card is a flex column, the outer grid handles the two-dimensional placement and the inner flexbox handles the one-dimensional stack inside each card. That combination is common and correct. The decision is not about page size or component size. It is about the number of axes you need to control.
CSS Layout One-Dimensional vs Two-Dimensional: What The Terms Actually Mean
One-dimensional layout means the algorithm processes items along a single axis. The other axis is only used for alignment or wrapping. Flexbox is one-dimensional. When flex-wrap: wrap creates multiple flex lines, each line is an independent flex container for cross-axis alignment. Items in different lines do not align with each other unless you use align-content, which aligns the lines as a group, not the items within them. Two-dimensional layout means the algorithm processes items along both axes at once, placing each item into a cell defined by a row track and a column track. Grid is two-dimensional. The explicit tracks in grid-template-columns and grid-template-rows define the grid, and items are placed into those tracks. Implicit tracks, created by grid-auto-rows and grid-auto-columns, handle items that do not fit into the explicit grid. Understanding explicit versus implicit tracks is the first step to using grid well. A common mistake: defining grid-template-columns and then expecting grid-auto-rows to behave like it, when it has its own default of auto.
Flexbox Grid Shared Alignment Properties: Where The Two Tools Overlap
Both flexbox and grid use the Box Alignment Module properties: justify-content, align-items, align-self, and gap. The justify-content property aligns items along the main axis in flexbox and along the inline axis in grid. align-items aligns items along the cross axis in flexbox and along the block axis in grid. The place-items shorthand sets align-items and justify-items in one declaration, and place-content sets align-content and justify-content. These shared properties are why the two tools feel similar at first, but the context differs. In flexbox, justify-content distributes space between items along a single line. space-between, space-around, and space-evenly are the common values. In grid, justify-content distributes the entire grid within its containing block if the grid is smaller than the container. Same property name, different behaviour. The gap property is also shared, but it shipped in flexbox later than in grid. Grid had gap from its initial release in March 2017. Flexbox gap arrived later across browsers. If you support older browsers, check the flexbox gap baseline on caniuse before relying on it.
FAQ: Flexbox vs Grid Questions That Come Up Every Time
When should I use flexbox instead of grid?
Use flexbox when you have a single row or a single column of items and you need to distribute space or align them along that one axis. Navigation bars, toolbars, and action button groups are flexbox use cases.
When should I use grid instead of flexbox?
Use grid when you have items that must align across both rows and columns: a form with labels and inputs, a dashboard of panels, or any layout with overlapping elements. Grid handles complex card grids where each card needs a uniform size.
Can I use grid inside a flexbox container?
Yes. A flex item can be a grid container. This is the common pattern of a card row: the outer flexbox handles the horizontal distribution, and each card is a grid for its internal layout.
Does subgrid work in all browsers?
This feature is baseline available since September 2023 in all major engines. It is safe to use in current browsers. For older browsers, provide a fallback: hard-code the track sizes, or use flexbox and accept the alignment loss.
Is the gap property the same in flexbox and grid?
The syntax is the same. The browser support history differs. Grid had gap from its initial release, while flexbox gap shipped later. In a codebase targeting browsers from before 2020, test flexbox gap carefully on caniuse.
| Scenario | Axis Count | Tool |
|---|---|---|
| Single row of nav links | One | Flexbox |
| Single column of stacked sections | One | Flexbox |
| Form with labels and inputs across rows | Two | Grid |
| Card grid with uniform cards | Two | Grid |
| Nested component with shared column widths | Two | Grid with subgrid |
| Toolbar with wrap and center alignment | One | Flexbox |
| Dashboard with panels in rows and columns | Two | Grid |
The Meta Question: Why This Page Exists
The one sentence on this page that no competitor could write is this: the 2014-era rule that grid is for page layout and flexbox is for components is not just outdated, it is actively wrong for any component that needs cross-row alignment, and subgrid is the feature that exposes the error. That sentence names the specific failure of the old rule and the specific feature that replaces it. It is the difference between a page that repeats what everyone says and a page that corrects what everyone says.