Layout
Overview
Layout is where Grids and Spacing meet the page: how wide content gets before it's capped and centered (containers), and the handful of shapes most screens are built from (page structure). Like Spacing, this foundation ships no new tokens — every value a container needs is already on Grids' breakpoint ladder or the master scale.
Principles
- Containers cap, they don't invent. A container's max-width and padding reuse Grids' and Spacing's existing tokens — nothing here is a new number.
- Name the shapes. A handful of named patterns (app shell, narrow form...) give a shared vocabulary so new pages don't each reinvent structure from scratch.
- Cap prose for readability, not everything. Long-form text gets a measure cap; containers in general don't need one.
- Restraint. Four named patterns, not an exhaustive taxonomy.
Tokens
This foundation adds none. It reuses:
| Need | Reuses | From |
|---|---|---|
| Container max-width | --breakpoint-sm/md/lg/xl/2xl | Grids |
| Container side padding | --scale-4 (below md) / --scale-6 (md and up) | Grids' gutter recipe |
.container {
width: 100%;
margin-inline: auto;
padding-inline: var(--scale-4);
}
@media (min-width: 48rem) { /* --breakpoint-md */
.container { padding-inline: var(--scale-6); max-width: var(--breakpoint-md); }
}
@media (min-width: 64rem) { .container { max-width: var(--breakpoint-lg); } }
@media (min-width: 80rem) { .container { max-width: var(--breakpoint-xl); } }
@media (min-width: 96rem) { .container { max-width: var(--breakpoint-2xl); } }
Named page patterns
| Pattern | Shape | Use for |
|---|---|---|
| Centered content | Single container, vertical stack, generous top/bottom spacing | Marketing pages, articles |
| App shell | Fixed-width sidebar + fluid main content area, persistent top bar | Dashboards, admin tools |
| Narrow form | Container capped well below lg, single column, centered vertically | Sign-in, sign-up, single-task flows |
| Full-bleed section | Content ignores the container, spans the full viewport width | Hero banners, dividers, image bands |
Rationale
Why does a container's max-width reuse --breakpoint-* instead of its own tokens? A container
that caps at exactly the breakpoint it was triggered by never exceeds the viewport it targets — and
that's the same number shadcn/Tailwind's own container utility already uses. A separate
--container-max-md at the identical value would be duplication with zero new information, the
same trap Spacing avoided with --space-md.
Why does container padding reuse Grids' gutter recipe instead of its own ladder? A container's edge padding and a grid's gutter solve the same problem — breathing room between content and the viewport edge. One recipe, tuned once, beats two that can silently drift apart.
Why four named patterns, not a general layout system? These are the shapes that recur across real products. Naming them ("this is an app shell") gives new pages a shared vocabulary without inventing a layout-engine abstraction a handful of named recipes doesn't yet need.
Why is the prose-readability cap guidance, not a token? ch is a font-relative unit with no
place on this system's rem/px-based scale, and the rule only applies to long-form text — not
every container. Turning it into a token would overstate it as system-wide when it's a targeted
rule of thumb.
Do / Don’t
Do
- Cap a container's width at the matching
--breakpoint-*value — never a bespoke max-width. - Reuse Grids' two-step gutter recipe for container padding.
- Name the page's structure when building it ("this is an app shell") so the next page matches.
- Cap long-form prose around 65–75 characters (
max-width: 65ch) for readability.
Don’t
- Invent a
--container-max-*or--container-padding-*token — reference Grids' and Spacing's existing tokens (Restraint). - Apply the prose-width cap to every container — it's for long-form text, not layout in general.
- Build a fifth page-structure pattern before a real, repeated need shows up.