Layout
Default to Grid. Use gap, not margin. Set constraints, not fixed dimensions. Let the browser do the work.
Grid vs Flexbox
The 1D vs 2D framing is a false distinction. The real question is who controls sizing.
Grid = parent controls
The container defines tracks and places content inside them. Columns are consistent regardless of content variation. Default for most layouts — including vertical stacks.
grid gap-4grid grid-cols-3 gap-4grid place-content-centerFlex = children control
Items negotiate their own sizes based on content. Ideal when layout should follow content — tags, nav items, pill lists, wrapping rows where items should be as wide as they need to be.
flex gap-4 items-centerflex flex-wrap gap-2Patterns
Vertical stack
grid gap-4 — the default vertical layout.
Centered content
grid place-content-center — one class centers both axes.
Centered in both axes
Horizontal row
flex gap-4 items-center — content-driven sizing.
Equal columns
grid grid-cols-3 gap-4 — parent controls column widths.
Responsive grid
grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6
Asymmetric layout
grid grid-cols-[1fr_2fr] gap-6
Wrapping row
flex flex-wrap gap-2 — items wrap naturally based on content width. This is where Flexbox shines: children control their own size.
Sizing
Set constraints, not fixed dimensions. Let content breathe and the layout flex.
Constraints over fixed
Use min-h- / max-w- instead of h- / w-. Fixed dimensions clip content. Constraints let it grow.
Trust browser defaults
Block elements default to width: auto which accounts for margins and padding. Don't set w-full or w-screen unless you have a concrete reason.
fit-content
w-fit sizes an element to its content. Useful for buttons, badges, and inline elements that shouldn't stretch.
fr and minmax()
Use fr units in grid templates to distribute available space. Use minmax(0, 1fr) to prevent content from forcing columns wider than intended.
Container
The container-* utility centers content with responsive horizontal padding and a configurable max width. It replaces the v1 <Container> component.
Usage
<div className="container-8xl">...</div><div className="container-4xl">...</div>Any --container-* token works: 3xs–7xl (Tailwind defaults) plus 8xl (1440px).
Responsive padding
| Breakpoint | Inline padding |
|---|---|
| Default | 1.5rem (24px) |
md (48rem) | 2rem (32px) |
lg (64rem) | 3rem (48px) |
Container queries
Components should respond to their parent, not the viewport. A card in a narrow sidebar needs different styling than the same card in a wide main column — but the viewport width is the same. Use @container for component-level adaptation.
Prefer container queries
Tailwind's @container class sets container-type: inline-size. Then use @sm:, @md:, @lg: etc. as container-query variants instead of sm:, md:.
Do
Respond to parent width so the component adapts regardless of where it is placed.
{/* Responds to viewport — breaks in narrow columns */}<div className="grid md:grid-cols-[auto_1fr]"><img /><div>Content</div></div>
Don’t
Respond to the viewport — it breaks when the same component is placed in a narrow column.
Live example — same component, different containers
Both cards use the same @sm:grid-cols-[80px_1fr] breakpoint. The narrow one stacks because its container is too small. The wider one goes side-by-side.
Narrow container
Stacks vertically — container is too narrow
Wider container
Goes side-by-side — same component, more space
Media queries for page-level layout. Container queries for component-level adaptation. Use both.
Spacing scale
Based on a 4px unit. Use with gap-, p-, m-, w-, h-.
0
0px
0.5
2px
1
4px
1.5
6px
2
8px
3
12px
4
16px
5
20px
6
24px
8
32px
10
40px
12
48px
16
64px
20
80px
24
96px
Best practices
| Do | Don't | Why |
|---|---|---|
| gap-4 | mb-4 on children | Gap never creates edge spacing |
| grid gap-4 | flex flex-col gap-4 | Grid is simpler for vertical stacks |
| grid place-content-center | flex items-center justify-center | One class centers both axes |
| grid grid-cols-3 | flex with calc(33%) | Grid handles equal columns natively |
| min-h-[200px] | h-[200px] | Content can grow beyond fixed height |
| max-w-4xl | w-full | Caps width, stays responsive |
| minmax(0, 1fr) | 300px fixed columns | Fixed units cause overflow on small screens |