Layout

Raw
synthesislatestRetrieved 2026-05-13

Spacing and Layout — Synthesis

Overview

A spacing system is a scale with a shared base unit that components and layouts consume to maintain proportional relationships across the UI. Its value is not any particular set of values — it is the discipline of enforcing a single coordinate system so that spacing decisions don't require per-element negotiation.


Base unit: 4px vs. 8px

Most production design systems use either 4px or 8px as the base grid unit. Both are practical. The choice matters less than using one consistently.

4px base (Radix, Material, Atlassian): More granular. Enables steps at 4, 8, 12, 16, 20, 24px — the tighter values (4px, 8px, 12px) are useful for component-internal spacing (icon gaps, badge padding, button icon margins) where 8px is often too large. A 4px base generates more usable steps without requiring half-steps or arbitrary values.

8px base (Carbon, many utility-class systems): Fewer steps, cleaner multiples. 8, 16, 24, 32, 40, 48px covers most layout and component needs. The coarser grid forces designers to commit more decisively — there are fewer values to disagree about.

The practical rule: Use 4px if your UI has dense components with many internal spacing decisions (data tables, form controls, navigation items). Use 8px if the product is more spacious and layout-level spacing dominates. Either way, never define arbitrary values outside the scale — if a value doesn't exist in the scale, that's a signal to round to the nearest step or to add the step.


The scale as a unified system

The spacing scale should connect three levels of the UI as a coherent system:

Component-internal spacing (4–16px range): gaps between an icon and its label, padding inside a button, space between form field label and input. These values are small and precise — the 4px half-steps matter here.

Component-to-component spacing (8–32px range): the gap between a heading and its body text, space between cards in a list, margin around a form group. This is where the rhythm of a UI becomes visible.

Layout-level spacing (16–64px range): section padding, page margins, major whitespace zones. These values create the breathing room that separates content regions and establishes visual hierarchy at the page level.

A scale that only works at one level fails at the others. A 4-step scale (8, 16, 24, 32) is insufficient for component-internal use. A scale with too many steps (Atlassian's 14-step scale from 2px to 80px) gives designers too much freedom and produces inconsistent results without strong convention.

A practical starting scale for a mixed product:

StepValueTypical use
14pxIcon gaps, badge padding, tight insets
28pxButton padding (vertical), small component gaps
312pxComponent padding (tight), between label and input
416pxStandard component padding, between list items
524pxBetween components in a section, card padding
632pxSection gaps, sidebar padding
748pxMajor layout gaps, section vertical padding
864pxLarge section whitespace, hero padding

Density axis

The density axis governs how tight or generous spacing is throughout a product. It is not a single value — it pervades every spacing decision.

Dense products (data-heavy apps, admin tools, dashboards) need: tighter component padding, smaller gaps between elements, and smaller step values used throughout the scale. A button with 8px vertical padding instead of 16px, a table row at 32px tall instead of 48px.

Spacious products (editorial, onboarding, marketing) need: generous padding, visible whitespace between sections, larger step values as defaults.

Design the density before designing the scale. A scale calibrated for a dense dashboard will feel cramped if repurposed for a marketing page; a spacious scale will waste screen space in a dense application.

For mixed products that need both densities, define a density axis rather than two separate scales:

  • A global scaling multiplier applied uniformly (Radix's scaling prop at 90–110%)
  • A discrete "compact/default/comfortable" mode that remaps specific spacing tokens
  • A set of density-variant component tokens for the highest-frequency components (tables, forms, navigation)

The multiplier approach is simpler to implement; the token-remap approach gives more granular control. Neither is universally correct.


Breakpoint philosophy

Content-first, not device-first. Define breakpoints at the sizes where your specific content needs to reflow — where the text measure becomes too wide, where the navigation no longer fits side-by-side, where the grid needs to collapse. Don't define breakpoints at device sizes (375, 768, 1024) unless those happen to coincide with your content's needs.

Minimize the number of breakpoints. Each additional breakpoint multiplies the design and implementation surface area. Most products need 3–4 breakpoints; more is usually a sign of premature specificity. Start with two (mobile, desktop), add a tablet breakpoint only when the content genuinely needs different treatment at that width.

Spacing should change at breakpoints, not just layout. It is common to restructure layouts at breakpoints (1 column → 2 columns) while leaving spacing unchanged. This is usually wrong — a component that was 24px padded on mobile often needs 32px or 40px on desktop because the surrounding whitespace has expanded. Define spacing tokens that are breakpoint-aware, or use responsive token values.

Responsive spacing approaches:

The simplest: define baseline scale values that are used as-is across all breakpoints, and override specific tokens at breakpoints where needed.

The more systematic: define spacing tokens as fluid values that scale smoothly between a min and max using clamp():

--space-section: clamp(24px, 5vw, 64px);

This eliminates hard breakpoints for spacing while maintaining the scale semantics. Best suited for layout-level spacing tokens; component-internal spacing rarely needs to be fluid.


The never-arbitrary rule

Every spacing value in a component or layout should reference a scale token or be derivable from one. A value of 17px is a design smell — it means a decision was made that bypasses the scale, which will need to be explained and justified every time someone reads the code.

When you feel the pull toward an off-scale value, ask: Is the scale missing a needed step? Is the component's internal padding trying to compensate for something else (wrong base font size, wrong line height)? Fixing the root cause is almost always better than introducing an off-scale value.