Skip to main content

Using spacing

Which step to use per case, worked examples with the tokens annotated, and the mistakes that survive review.

Version: 3.0.0-beta

Overview gives you two questions to pick a step with. This page turns them into specific answers, shows the tokens on the elements themselves, and lists what tends to go wrong.

Inline and block​

Inline and block describe direction relative to the flow of the content, rather than fixed sides of the screen.

AxisWhat it followsIn horizontal text
Inlinethe direction a line of text is writtenleft and right
Blockthe direction lines and elements are stackedtop and bottom

For example, padding-inline adds space before and after content on the inline axis, while padding-block adds space before and after it on the block axis. These logical properties adapt to right-to-left and vertical writing modes, unlike padding-left, padding-right, padding-top and padding-bottom.

Decision table​

The gap rows are the two questions already answered for common cases. Padding depends on the component, so this table is where to look it up. If your case is not here, the nearest row is usually right.

You are spacingUseWhy
a button's interior, block axisspacing.xstext needs less room above it than beside it
a button's interior, inline axisspacing.mdand more beside it, or the label looks off-centre
an icon from its label, inside a controlspacing.xsone control, two parts
a chip or badge interiorspacing.3xsdense by definition. 2xs if it carries an icon
an input's interiorspacing.xs block, spacing.sm inlineshorter inline than a button: the value needs to look aligned with the label above it
one field from the nextspacing.smrelated, separate
one fieldset from the nextspacing.lga group boundary
a card's interiorspacing.mdthe default container padding
a card's children from each otherspacing.smrelated items in a group
a list row's interiorspacing.sm block, spacing.md inlinerows read as a stack, so the block axis stays tighter
a table cell's interiorspacing.2xs block, spacing.sm inlineand then use Compact density rather than shrinking these
one section of a card or dialog from the nextspacing.xla boundary inside one container
one section of a page from the nextspacing.7xla page-level boundary
one section from the next, on a long pagespacing.8xla boundary that has to read as a break in the page
a page gutterspacing.2xl or spacing.3xllayout, outside any component
one major region of a page from anotherspacing.5xlthe gap between a sidebar and its content, or a header and the body
full-page compositionspacing.9xlthe widest step, for the space around a whole page of content

Worked examples​

Each diagram is rendered from the tokens it names, so the labels cannot describe something the element is not doing. The values are read back from the browser after layout, which is why they follow the density around them.

Padding a control​

Add itemcorner-radius.roundedspacing.xsblock paddingspacing.mdinline padding
A button at Comfortable density. Horizontal and vertical padding are different steps on purpose.
.button {
padding-block: var(--eds-spacing-xs);
padding-inline: var(--eds-spacing-md);
gap: var(--eds-spacing-xs);
border-radius: var(--eds-corner-radius-rounded);
}

Two steps apart on the two axes is deliberate rather than sloppy. Text needs more room beside it than above it to look optically centred, because the letterforms already carry their own vertical space in the line box. Equal padding on both axes reads as too tight horizontally.

A focus ring​

Worth including because it is the one place corner-radius.rounded-outer shows up, and because the code and the Figma file get there differently.

In code, a focus ring is an outline with an outline-offset. The browser follows the element's own border-radius and widens it by the offset, so the ring's curve comes out right without naming a second radius:

.button {
border-radius: var(--eds-corner-radius-rounded); /* 4px at Comfortable */
}
.button:focus-visible {
outline: 2px solid var(--eds-border-interactive-focus);
outline-offset: 1px; /* the ring's inner edge comes out at 5px on its own */
}

Figma has no outline-offset. A ring there is a separate rectangle behind the element, and it needs its radius set explicitly, one step larger than the element it surrounds. corner-radius.rounded-outer is that value, which is why it is rounded plus 1px: the same 1px the CSS offset adds.

So the token is a workaround for one tool, rather than a radius with a design meaning. Do not use it in code, and do not use it for nested containers. If a container around a rounded child needs a particular corner, set that corner.

A compact table​

Switching density is one attribute on a wrapper. Nothing in the markup below it changes, and no spacing token in it is re-picked:

Well

Status

Depth

31/2-A-14

Producing

2 940 m

31/2-B-07

Shut in

3 120 m

<section data-density="compact">
<table>
…
</table>
</section>
td,
th {
padding: var(--eds-spacing-2xs) var(--eds-spacing-sm);
}

Density can be set on any ancestor and it cascades, so a compact table inside a comfortable page is a normal thing to want. Two cautions:

  • Do not nest a looser density inside a tighter one to undo it. Set the density once, where the content changes. relaxed inside compact inside relaxed is legal CSS and unreadable design.
  • Compact reduces hit area. Less padding means a smaller target, so do not use Compact for a primary touch interface. That is what Relaxed is for.

Do's and Don'ts​

Do
  • Use spacing.none when you mean zero. It states the intent and survives a density change
  • Pick by relationship, so the same pairing gets the same step on every page
  • Let density resize things, with one attribute on a wrapper
  • Use different steps on the block and inline axes when the optics need it
  • Let a focus ring's outline-offset produce its curve, rather than naming a second radius
Don't
  • Write a hard 0. It is indistinguishable from a value nobody set
  • Hand-pick a smaller step through a dense area. That reimplements Compact badly and drifts from every other dense view in the product
  • Use a spacing token for a component's height. Height falls out of type size plus padding
  • Use a spacing token for icon size. They resolve to the same values today, so it works, and it breaks silently the day icon sizing changes
  • Use corner-radius.rounded-outer. It exists for Figma's focus rings, not for code
  • Space everything equally. If every gap is md, nothing is grouped

Where to go next​

  • Token reference: every token and every value, in all three densities.
  • The scale: why the steps are these sizes, and how density maps onto them.