Layouts
Composable primitives for page structure. Container, Grid, Stack, Cluster, Split, Sidebar, and Center — combine them to build any layout without writing custom CSS.
Container
Centers content with a max-width and horizontal padding.
--narrow 640px
default 960px
--wide 1280px
<div style="display: flex; flex-direction: column; gap: var(--space-3); width: 100%;">
<div class="Layout-container Layout-container--narrow" style="background: var(--accent-s); padding: var(--space-3); border-radius: var(--r-s); border: 1px dashed var(--accent);">
<code style="font-size: .75rem; color: var(--accent);">--narrow</code> <span style="color: var(--fg-3); font-size: .8rem;">640px</span>
</div>
<div class="Layout-container" style="background: var(--bg-s); padding: var(--space-3); border-radius: var(--r-s); border: 1px dashed var(--bd-s);">
<code style="font-size: .75rem;">default</code> <span style="color: var(--fg-3); font-size: .8rem;">960px</span>
</div>
<div class="Layout-container Layout-container--wide" style="background: var(--bg-s); padding: var(--space-3); border-radius: var(--r-s); border: 1px dashed var(--bd-s);">
<code style="font-size: .75rem;">--wide</code> <span style="color: var(--fg-3); font-size: .8rem;">1280px</span>
</div>
</div>
<div class="Layout-container">...</div>
<div class="Layout-container Layout-container--narrow">...</div>
<div class="Layout-container Layout-container--wide">...</div>
Grid
A 24-column fluid grid. All columns collapse to full-width below 768px. Use Layout-col-{n}@md for responsive spans. The 24-column system gives finer control — thirds (8-col), halves (12-col), quarters (6-col), and asymmetric splits like 16/8 or 18/6.
<div class="Layout-grid" style="width: 100%;">
<div class="Layout-col-8" style="background: var(--accent); color: white; padding: var(--space-3); border-radius: var(--r-s); text-align: center; font-weight: 600;">8</div>
<div class="Layout-col-8" style="background: var(--accent); color: white; padding: var(--space-3); border-radius: var(--r-s); text-align: center; font-weight: 600;">8</div>
<div class="Layout-col-8" style="background: var(--accent); color: white; padding: var(--space-3); border-radius: var(--r-s); text-align: center; font-weight: 600;">8</div>
</div>
<div class="Layout-grid" style="width: 100%;">
<div class="Layout-col-16" style="background: oklch(55% 0.15 270); color: white; padding: var(--space-4); border-radius: var(--r-s); font-weight: 600;">16 — Main</div>
<div class="Layout-col-8" style="background: oklch(75% 0.08 270); padding: var(--space-4); border-radius: var(--r-s);">8 — Side</div>
</div>
<div class="Layout-grid">
<div class="Layout-col-16">Main content</div>
<div class="Layout-col-8">Sidebar</div>
</div>
<!-- Responsive: full on mobile, halves on tablet+ -->
<div class="Layout-grid">
<div class="Layout-col-24 Layout-col-12@md">Left</div>
<div class="Layout-col-24 Layout-col-12@md">Right</div>
</div>
Stack
Vertical flow with consistent gap. The most-used layout primitive.
<div style="display: flex; gap: var(--space-8); align-items: flex-start;">
<div style="text-align: center;">
<div style="font-size: .7rem; font-weight: 600; text-transform: uppercase; letter-spacing: .05em; color: var(--fg-4); margin-bottom: var(--space-2);">Tight · 8px</div>
<div class="Layout-stack Layout-stack--tight" style="width: 80px;">
<div style="background: var(--accent); height: 24px; border-radius: var(--r-s);"></div>
<div style="background: var(--accent); height: 24px; border-radius: var(--r-s);"></div>
<div style="background: var(--accent); height: 24px; border-radius: var(--r-s);"></div>
</div>
</div>
<div style="text-align: center;">
<div style="font-size: .7rem; font-weight: 600; text-transform: uppercase; letter-spacing: .05em; color: var(--fg-4); margin-bottom: var(--space-2);">Default · 16px</div>
<div class="Layout-stack" style="width: 80px;">
<div style="background: var(--accent); height: 24px; border-radius: var(--r-s);"></div>
<div style="background: var(--accent); height: 24px; border-radius: var(--r-s);"></div>
<div style="background: var(--accent); height: 24px; border-radius: var(--r-s);"></div>
</div>
</div>
<div style="text-align: center;">
<div style="font-size: .7rem; font-weight: 600; text-transform: uppercase; letter-spacing: .05em; color: var(--fg-4); margin-bottom: var(--space-2);">Loose · 32px</div>
<div class="Layout-stack Layout-stack--loose" style="width: 80px;">
<div style="background: var(--accent); height: 24px; border-radius: var(--r-s);"></div>
<div style="background: var(--accent); height: 24px; border-radius: var(--r-s);"></div>
<div style="background: var(--accent); height: 24px; border-radius: var(--r-s);"></div>
</div>
</div>
</div>
<div class="Layout-stack">...</div>
<div class="Layout-stack Layout-stack--tight">...</div>
<div class="Layout-stack Layout-stack--loose">...</div>
Cluster
Horizontal grouping with wrapping. For tags, buttons, inline elements.
<div class="Layout-cluster">
<span class="Badge Badge--primary">Design</span>
<span class="Badge">Development</span>
<span class="Badge">Product</span>
<span class="Badge">Research</span>
<span class="Badge">Strategy</span>
<span class="Badge">Engineering</span>
</div>
<div class="Layout-cluster">
<span class="Badge">Tag</span>
<span class="Badge">Tag</span>
...
</div>
Split
Push items to opposite ends of a row. Headers, footers, toolbars.
<div class="Layout-split" style="width: 100%; background: var(--bg-s); padding: var(--space-3) var(--space-4); border-radius: var(--r-s);">
<span style="font-weight: 600;">Page Title</span>
<button class="Button Button--primary Button--small">Action</button>
</div>
<div class="Layout-split">
<h1>Title</h1>
<button class="Button">Action</button>
</div>
Sidebar
Fixed-width sidebar with fluid main area. Stacks on mobile. Use --right to flip.
<div class="Layout-sidebar" style="width: 100%;">
<aside style="background: var(--bg-m); padding: var(--space-4); border-radius: var(--r-s);">
<strong style="font-size: .85rem;">Sidebar</strong>
<div style="color: var(--fg-3); font-size: .75rem; margin-top: var(--space-1);">240px fixed</div>
</aside>
<main style="background: var(--bg-s); padding: var(--space-4); border-radius: var(--r-s);">
<strong style="font-size: .85rem;">Main Content</strong>
<div style="color: var(--fg-3); font-size: .75rem; margin-top: var(--space-1);">Fluid width, fills remaining space</div>
</main>
</div>
<div class="Layout-sidebar">
<aside>Navigation</aside>
<main>Content</main>
</div>
<!-- Sidebar on right -->
<div class="Layout-sidebar Layout-sidebar--right">
<main>Content</main>
<aside>Sidebar</aside>
</div>
Center
Vertical and horizontal centering. Empty states, loading screens.
<div class="Layout-center" style="height: 160px; width: 100%; background: var(--bg-s); border-radius: var(--r-s);">
<div style="text-align: center;">
<div style="font-size: 1.5rem; margin-bottom: var(--space-2);">📭</div>
<div style="font-weight: 600; font-size: .9rem;">Nothing here yet</div>
<div style="color: var(--fg-3); font-size: .8rem;">Create your first item to get started.</div>
</div>
</div>
<div class="Layout-center" style="min-height: 300px;">
<div>Centered content</div>
</div>
Composition
These primitives are designed to nest. A typical page:
<div class="Layout-container">
<div class="Layout-stack Layout-stack--loose">
<header class="Layout-split">
<h1>Dashboard</h1>
<button class="Button Button--primary">New</button>
</header>
<div class="Layout-sidebar">
<aside class="Layout-stack">
<!-- Nav links -->
</aside>
<main class="Layout-stack">
<div class="Layout-grid">
<div class="Layout-col-8">Stat card</div>
<div class="Layout-col-8">Stat card</div>
<div class="Layout-col-8">Stat card</div>
</div>
<!-- Content -->
</main>
</div>
</div>
</div>
API Reference
| Class | Description |
|---|---|
.Layout-container |
Centered container, 960px max-width |
.Layout-container--narrow |
640px max-width |
.Layout-container--wide |
1280px max-width |
.Layout-grid |
24-column fluid grid |
.Layout-col-{1-24} |
Column span |
.Layout-col-{1-24}@md |
Column span at 768px+ |
.Layout-stack |
Vertical flow, 16px gap |
.Layout-stack--tight |
8px gap |
.Layout-stack--loose |
32px gap |
.Layout-cluster |
Horizontal wrapping group |
.Layout-split |
Space-between row |
.Layout-sidebar |
Sidebar (240px) + fluid main |
.Layout-sidebar--right |
Sidebar on the right |
.Layout-center |
Vertical + horizontal centering |
Best Practices
Do
- ✓ Start with Container — Wrap page content in
Layout-containerto constrain width and center the layout - ✓ Use Stack as your default — Most vertical arrangements should use
Layout-stackrather than custom margins - ✓ Compose primitives — Nest Grid inside Stack inside Container; these are building blocks, not standalone solutions
- ✓ Use responsive column classes — Apply
Layout-col-24 Layout-col-12@mdso layouts collapse gracefully on mobile - ✓ Choose the right gap — Use
--tightfor related items (form fields), default for sections,--loosefor page-level spacing
Don’t
- ✗ Add custom margins between layout children — Let the layout primitive’s gap handle spacing
- ✗ Use Grid for simple vertical stacking — A 1-column grid is just a Stack; use the simpler primitive
- ✗ Hardcode widths on grid columns — Use
Layout-col-{n}classes instead of inline width styles - ✗ Nest grids deeply — More than two levels of Grid nesting becomes hard to maintain; flatten with Stack or Split
- ✗ Forget the Container — Without it, content stretches edge-to-edge on wide screens and becomes unreadable
CSS Reference
/* ── Container ── */
.Layout-container {
width: 100%;
max-width: 960px;
margin-inline: auto;
padding-inline: var(--space-4);
}
.Layout-container--narrow {
max-width: 640px;
}
.Layout-container--wide {
max-width: 1280px;
}
/* ── Grid (24-column) ── */
.Layout-grid {
display: grid;
grid-template-columns: repeat(24, 1fr);
gap: var(--space-4);
}
.Layout-col-1 { grid-column: span 1; }
.Layout-col-2 { grid-column: span 2; }
.Layout-col-3 { grid-column: span 3; }
.Layout-col-4 { grid-column: span 4; }
.Layout-col-5 { grid-column: span 5; }
.Layout-col-6 { grid-column: span 6; } /* Quarter */
.Layout-col-7 { grid-column: span 7; }
.Layout-col-8 { grid-column: span 8; } /* Third */
.Layout-col-9 { grid-column: span 9; }
.Layout-col-10 { grid-column: span 10; }
.Layout-col-11 { grid-column: span 11; }
.Layout-col-12 { grid-column: span 12; } /* Half */
.Layout-col-13 { grid-column: span 13; }
.Layout-col-14 { grid-column: span 14; }
.Layout-col-15 { grid-column: span 15; }
.Layout-col-16 { grid-column: span 16; } /* Two-thirds */
.Layout-col-17 { grid-column: span 17; }
.Layout-col-18 { grid-column: span 18; } /* Three-quarters */
.Layout-col-19 { grid-column: span 19; }
.Layout-col-20 { grid-column: span 20; }
.Layout-col-21 { grid-column: span 21; }
.Layout-col-22 { grid-column: span 22; }
.Layout-col-23 { grid-column: span 23; }
.Layout-col-24 { grid-column: span 24; } /* Full */
@media (min-width: 768px) {
.Layout-col-1\@md { grid-column: span 1; }
/* ... spans 2-23 ... */
.Layout-col-12\@md { grid-column: span 12; }
.Layout-col-24\@md { grid-column: span 24; }
}
/* ── Stack ── */
.Layout-stack {
display: flex;
flex-direction: column;
gap: var(--space-4);
}
.Layout-stack--tight {
gap: var(--space-2);
}
.Layout-stack--loose {
gap: var(--space-8);
}
/* ── Cluster ── */
.Layout-cluster {
display: flex;
flex-wrap: wrap;
gap: var(--space-2);
align-items: center;
}
/* ── Split ── */
.Layout-split {
display: flex;
justify-content: space-between;
align-items: center;
gap: var(--space-4);
}
/* ── Sidebar ── */
.Layout-sidebar {
display: flex;
gap: var(--space-4);
}
.Layout-sidebar > aside {
flex: 0 0 240px;
}
.Layout-sidebar > main {
flex: 1 1 0%;
min-width: 0;
}
.Layout-sidebar--right {
flex-direction: row-reverse;
}
@media (max-width: 767px) {
.Layout-sidebar {
flex-direction: column;
}
.Layout-sidebar > aside {
flex: none;
}
}
/* ── Center ── */
.Layout-center {
display: flex;
align-items: center;
justify-content: center;
}