Layout
How layout works, designed outside-in: the two frames you design on, the shell that divides the viewport, the container that is your real canvas, the grid that divides it, the max widths that cap content, and the Figma-to-code mapping that keeps what you draw identical to what ships.
What you design on
2 framesYou design two frames, not seven breakpoints: a mobile frame at 375 and a desktop frame at 1440. The seven breakpoints are code’s dial: lg (1024px) is the only moment the layout changes shape, and content caps at 1280px, so wider frames add margin, not design. Everything on this page exists so that what you draw at these two sizes is exactly what the browser builds.
Frame | Panels | Content margins | Content width |
|---|---|---|---|
| Mobile · 375 | – | 16px each side | 343px |
| Marketing · 1440 | – | 112px each side | 1,216px |
| Application · 1440 | 280px left | 312px left · 32px right | 1,096px |
| App + right panel · 1920 | 280px × 2 | 352px each side | 1,216px |
Design represents the build
Every number in that table is measured from the shipped code: the shell’s 280px sidebar (w-70), the container’s px-4 / lg:px-8 gutters, and the 1,280px max-w-container cap. If theme.css changes, these numbers change with it; the live tables below always carry the current truth.
The shell: persistent UI and main
The shell is the persistent UI that frames your content: the navigation sidebar, top bars, and side panels that stay put while the page scrolls (you’ll sometimes hear this layer called chrome). An application shell is persistent UI plus a scrolling main: the shell divides the viewport, the sidebar holds at 280px from lg up, an optional right panel for global tools follows the pinning rule below, and main takes everything left. You design what happens inside main; the system owns the frame around it. A marketing page drops the persistent UI and stacks full-width bands instead. Drag the viewport and watch the division happen.
main (1160px) is under the 1280px cap: the container is fluid and fills it
The right panel (application shell only)
An application shell may add a second fixed panel on the right for global tools and widgets, the same 280px width as the navigation sidebar. Its one rule: it never squeezes the main content. The panel pins to the right edge of the browser only when there is mathematically room for it beside uncompromised content: sidebar + content cap + panel, which is 280 + 1,280 + 280 = 1,840px of viewport with today’s tokens. Below that, the panel docks behind an icon in the top-right of the header and opens as a drawer overlaying the main content (never pushing it) and closes back out of the way. When both panels are pinned, the content centers between them. Toggle the right panel in the simulator and drag across 1,840px to watch it dock and pin.
Application shell · sticky sidebar + scrolling main
Marketing page · full-width bands, contained content
The container: your actual canvas
Main is not your canvas; the container inside it is. Every page region wraps its content in max-w-container mx-auto px-4 lg:px-8: fluid until the main column passes 1,280px, then capped and centered. Drag the simulator above past ~1,580px in application mode and watch the container stop growing; that is the only sense in which sidebar and container widths ever add up. The variables below hold the container’s measurements, measured live from the tokens.
Name | Tailwind | Size (16px base) | Pixels | Size |
|---|---|---|---|---|
| px-4 | 1rem | 16px | ||
| lg:px-8 | 2rem | 32px | ||
| max-w-container | 80rem | 1,280px |
Dividing the canvas: the grid
How do sibling blocks share the canvas? Proportionally, on a grid. Figma’s 12-column layout grid maps one-to-one to grid-cols-12 plus col-span-*; a span is a fraction of the container, so the layout redistributes as the container changes, and a span keeps meaning half or a third at any width. There is no single global gutter in code: gaps come from the spacing scale per layout, so set your Figma gutter to the gap you intend to spec.
You want | In Figma | In code |
|---|---|---|
| Columns to design on | Layout grid · 12 columns | grid grid-cols-12 |
| A block half the canvas wide | Span 6 of the 12 columns | col-span-6 |
| Full width on phone, half on desktop | 375: span 12 · 1440: span 6 | col-span-12 lg:col-span-6 |
| Space between the columns | Gutter = the gap you spec | gap-4 16 · gap-6 24 · gap-8 32 |
Two thirds + one third: main (col-span-8) and aside (col-span-4), stacking to full width on mobile
Capping content: max widths
How wide may one block get, regardless of layout? A max width is an absolute ceiling tied to the content: below it the block stays fluid and keeps shrinking with the viewport; at it, the block stops growing. In Figma this is a fixed-width block centered in its region; in code it is w-full max-w-* mx-auto, usually applied from a breakpoint (md:max-w-120) because mobile is full-width anyway. width-sm (480px) is the workhorse, covering hero leads, CTA rows, and form columns; the paragraph measure (720px, max-w-180) caps running prose.
Name | Tailwind | Size (16px base) | Pixels | Width |
|---|---|---|---|---|
| max-w-80 | 20rem | 320px | ||
| max-w-96 | 24rem | 384px | ||
| max-w-120 | 30rem | 480px | ||
| max-w-140 | 35rem | 560px | ||
| max-w-160 | 40rem | 640px | ||
| max-w-192 | 48rem | 768px | ||
| max-w-256 | 64rem | 1,024px | ||
| max-w-320 | 80rem | 1,280px | ||
| max-w-360 | 90rem | 1,440px | ||
| max-w-400 | 100rem | 1,600px | ||
| max-w-480 | 120rem | 1,920px | ||
| max-w-180 | 45rem | 720px |
The two tools compose. Below, the grid gives the main region two thirds of the canvas; the form column inside it stops at 480px no matter how wide that region grows. The unused space stays visible; that is the cap doing its job.
A 480px form column (max-w-120) inside a two-thirds main region: the grid shares space, the cap protects content
Don’t fake one with the other
Don’t fake a cap with col-span; a proportion drifts as the container changes. Don’t fake columns with side-by-side caps; they don’t distribute space or sit on the 12-column rhythm. The grid decides a region’s share; a max width protects the content inside it.
Breakpoints
7 stepsBreakpoints measure the viewport, never the main column: at a 1,280px viewport with the sidebar open, an xl: style is active even though main is only 1,000px wide. That is why lg (1024px) is the moment that matters: it is when the sidebar appears and the gutters widen, and why your two frames are the mobile base and 1440. The full scale below is code’s reference. The recipes under it show what a breakpoint change actually looks like: each pair is the same layout drawn at both of your frames.
Prefix | Min width | Rem | What changes | Width |
|---|---|---|---|---|
| 320px | 20rem | Kit addition for the smallest phones; currently unused. | ||
| 600px | 37.5rem | Kit addition matching Sonner’s toast breakpoint. | ||
| 640px | 40rem | First density step: galleries widen, stacks go horizontal. | ||
| 768px | 48rem | The kit’s workhorse for component-level switches. | ||
| 1,024px | 64rem | The desktop moment: sidebar, wider gutters, app layouts. | ||
| 1,280px | 80rem | Matches the container max width; rare in components. | ||
| 1,536px | 96rem | Almost never needed: content caps at 1280px. |
Stacks become rows · flex-col lg:flex-row
Grids get denser · grid-cols-2 sm:grid-cols-3 lg:grid-cols-6
Navigation moves · top bar on mobile, sidebar from lg
Margins widen · 16px (px-4) to 32px (lg:px-8)
Layout inside components
The same system at component scale, and the strongest Figma-to-code bridge in the kit: auto layout is flexbox. Vertical auto layout with a gap is flex-col gap-*; horizontal with centered alignment is flex items-center gap-*; small form grids are grid gap-* sm:grid-cols-2. Gaps always come from the spacing scale: a 12px auto-layout gap is gap-3, never an ad-hoc margin.
You do in Figma | The system builds it with |
|---|---|
| Auto layout · vertical, gap 12 | flex flex-col gap-3 |
| Auto layout · horizontal, gap 12, align center | flex items-center gap-3 |
| Auto layout padding 16 | p-4 |
| Fixed 480 block, centered in its region | w-full max-w-120 mx-auto |
| Hug contents / fill container | w-max / flex-1 or w-full |
Stack · flex flex-col gap-3
Row · flex items-center gap-3
Form grid · grid gap-3 sm:grid-cols-2
A screen, torn down
this pageThis page, read the way the system reads it. Every layout decision on the screen you are looking at is one of the tools above, numbered in the schematic and named in the legend.
- 1Persistent UI. The sticky 280px sidebar (
w-70): the shell divides the viewport before anything else happens. - 2The container.
max-w-container mx-auto px-4 lg:px-8. Every block below sits inside it. - 3The grid. Section intros are
grid-cols-12with the text oncol-span-12 lg:col-span-6(half the canvas on desktop, full width on mobile). - 4The measure. Body copy caps at
max-w-180(720px) for line length. - 5The spacing scale.
gap-28between sections,gap-10within them,gap-6between demo and table; every gap is a step, never an ad-hoc margin.