Spacing
Spacing provides a shared scale for controlling the space within components and between interface elements.
The scale uses fluid values generated with Utopia for the needs of each project. It includes individual spacing sizes, responsive pairs, and gutter values.
These tokens create consistent spatial relationships without requiring separate declarations at every breakpoint.
Generating the spacing scale
Generate the spacing tokens with the Utopia fluid space calculator.
The spacing calculator uses the same minimum and maximum viewport widths and base font sizes as the project’s fluid type scale. It then applies configurable multipliers to generate a related spacing palette.
Choose:
- the minimum and maximum viewport widths
- the base font size at each viewport
- the spacing sizes and their multipliers
- the required one-up pairs
- any required custom pairs
Use space as the generated token prefix.
Copy the generated CSS into the project’s spacing tokens and preserve the generated Utopia link comment:
/* @link https://utopia.fyi/space/calculator?... */
:root {
--space-3xs: ...;
--space-2xs: ...;
--space-xs: ...;
--space-s: ...;
--space-m: ...;
--space-l: ...;
--space-xl: ...;
--space-2xl: ...;
--space-3xl: ...;
}The link records the calculator settings used to produce the scale.
Update the configuration through Utopia instead of editing individual generated clamp() values manually.
The configuration is project-specific. Its viewport range, base sizes, and spacing multipliers should support the project’s typography, content density, and visual direction.
Individual spaces
The individual spacing scale contains nine named sizes:
--space-3xs
--space-2xs
--space-xs
--space-s
--space-m
--space-l
--space-xl
--space-2xl
--space-3xlEach token transitions fluidly between its configured minimum and maximum value.
The scale names describe relative size:
3xs < 2xs < xs < s < m < l < xl < 2xl < 3xl
They do not prescribe a specific use. For example, --space-m is not automatically card padding or section spacing.
Use an individual space when the relationship should remain at the same position in the scale across the viewport range.
.card {
padding: var(--space-m);
gap: var(--space-s);
}Both values grow fluidly, but --space-m remains the medium spacing value and --space-s remains the small value.
One-up pairs
One-up pairs transition from one spacing step at the minimum viewport to the next step at the maximum viewport.
--space-3xs-2xs
--space-2xs-xs
--space-xs-s
--space-s-m
--space-m-l
--space-l-xl
--space-xl-2xl
--space-2xl-3xlFor example:
.section {
padding-block: var(--space-l-xl);
}At the narrow end of the configured viewport range, the value begins at the project’s l size. At the wide end, it reaches the project’s xl size.
Use a one-up pair when the spacing relationship should become moderately more generous as available space increases.
Utopia generates these pairs from the individual spacing values and allows them to vary more substantially than a single spacing token.
Custom pairs
Custom pairs transition between non-adjacent spacing steps.
--space-s-l
--space-m-xl
--space-l-2xlFor example:
.hero {
padding-block: var(--space-l-2xl);
}This moves from the l value at the minimum viewport to the 2xl value at the maximum viewport.
Use a custom pair when a relationship needs a deliberately larger responsive change, such as:
- major page-section spacing
- prominent composition spacing
- large hero padding
- substantial changes between compact and expansive layouts
Do not use a wide custom pair merely because it produces a more visibly responsive effect. Its minimum and maximum values should both be appropriate for the content and layout.
Utopia allows custom pairs to be built from any two configured individual space values.
Choosing a spacing token
Choose the smallest token that creates the required visual relationship.
Consider:
- Relationship: How closely are the elements related?
- Context: Is the space inside a component or between major page regions?
- Density: Should the interface feel compact or spacious?
- Responsiveness: Should the relationship remain stable or change substantially?
- Content: Can the spacing tolerate longer text, wrapping, and translated content?
Use an individual token when the relationship should scale gently:
.field {
display: grid;
gap: var(--space-2xs);
}Use a pair when the relationship should change more noticeably:
.page-section {
padding-block: var(--space-l-2xl);
}Applying spacing
Use spacing tokens with layout properties such as:
.component {
gap: var(--space-s);
padding-block: var(--space-m);
padding-inline: var(--space-s-m);
margin-block-start: var(--space-l);
}Prefer gap when spacing repeated flex or grid children:
.actions {
display: flex;
flex-wrap: wrap;
gap: var(--space-xs);
}This keeps spacing attached to the relationship between children rather than to the position of a particular child.
Use logical properties where the spacing represents the start, end, inline, or block direction:
.notice {
padding-block: var(--space-s);
padding-inline: var(--space-m);
margin-block-end: var(--space-l);
}Component and page spacing
The same scale can serve both component and page layouts, but their needs differ.
Component spacing commonly uses the smaller and middle parts of the scale:
--space-3xs
--space-2xs
--space-xs
--space-s
--space-mPage composition commonly requires larger spaces or responsive pairs:
--space-l
--space-xl
--space-2xl
--space-3xl
--space-l-xl
--space-xl-2xlThese are tendencies, not restrictions. Choose the token according to the actual relationship rather than the category of the element.
Gutters
Gutter tokens provide the spacing between page content and the viewport or containing layout boundary.
--gutter-xs
--gutter-s
--gutter-m
--gutter-l
--gutter-xl
--gutter-2xlGutters use explicit role-based names because they belong to page layout rather than the general spacing scale.
.page {
padding-inline: var(--gutter-s);
}The Spacing foundation owns the gutter values. The Layout foundation defines how those values are assigned across responsive ranges and used with containers and grids.
Do not use gutter tokens as general replacements for --space-* tokens inside components.
Avoid arbitrary values
Use the spacing scale for recurring interface relationships:
/* Preferred */
.card {
padding: var(--space-m);
gap: var(--space-s);
}Avoid introducing an arbitrary value when an existing token satisfies the relationship:
/* Avoid without a specific reason */
.card {
padding: 1.4375rem;
gap: 0.8125rem;
}An arbitrary value can still be appropriate when:
- the value is determined by an external asset
- the value is required for precise alignment
- the value represents a fixed technical constraint
- no spacing token creates the required result
Do not add another global spacing token for a single local exception.
Do not calculate with token names
Do not assume that a token is a fixed multiple of another token:
/* Avoid */
padding: calc(var(--space-s) * 2);Fluid tokens can use different minimum and maximum relationships. Multiplying one token does not necessarily reproduce another step in the configured scale.
Use the intended token directly:
padding: var(--space-l);Use calc() when the calculation itself represents a real layout relationship, not as a substitute for selecting from the spacing scale.
Adding or changing spacing tokens
Change the generated scale when:
- a recurring relationship cannot be represented by the existing values
- the project needs another minimum or maximum spacing size
- a responsive relationship repeatedly needs the same custom pair
- the existing scale does not support the intended content density
Before adding a custom pair, confirm that it will be reused.
After changing the Utopia configuration:
- replace the generated spacing declarations
- preserve the updated generator link
- test existing component and page layouts
- check the minimum and maximum viewport sizes
- check intermediate widths
- verify that spacing remains appropriate when content wraps or expands
Do not rename existing spacing tokens according to one component’s use. Their names should remain relative and reusable.
Accessibility
Spacing must tolerate changes to text and content.
Check that:
- text resizing does not cause content to overlap or become clipped
- increased text spacing does not break fixed-height components
- interactive controls remain visually distinct
- focus indicators are not obscured by overflow or tightly packed elements
- touch and pointer targets are not made difficult to operate by insufficient separation
- important relationships remain understandable when content wraps
- zoomed layouts preserve a clear reading and interaction order
Spacing can support usability, but it does not replace the size and behaviour requirements of the component being spaced.