A consistent scale for padding, margins, gaps, and other spatial relationships. Every step is a multiple of one unit, the --spacing-unit custom property: md is calc(var(--spacing-unit, 0.4rem) * 4). The unit defaults to 4px (SPACING_UNIT_PX), written in rem against the design system’s 10px root (html { font-size: 62.5% }), so md is 16px and the scale still follows the user’s browser font size.
The sub-unit steps (5xs–2xs) cover hairline gaps that dense UI needs: 5xs is a quarter of the unit (1px), 4xs half (2px), 3xs one unit (4px) and 2xs one and a half (6px). From md (4 units, 16px) upward the scale is linear, +1 unit per step. none is a literal 0, handy for resetting a gap inside a responsive object.
data-density="compact" or "relaxed" on an element swaps the unit to 3px or 5px for everything inside it, and every step keeps its multiplier: md is 12px compact, 16px default, 20px relaxed. Control-row padding and gaps follow, because they are spacing tokens; control heights, type and the 24px raster line stay put. The Appearance block sets it on <html> and remembers the choice.
<html data-density="compact">
…
</html>
<aside data-density="compact">…</aside>
<!-- or any subtree -->
default is the absence of the attribute.
The raster counts vertical space in text lines, and one line is 24px (16px × 1.5) — exactly 6 spacing units. So the spacing scale nests inside the line, but only two tokens land on a whole number of lines: xl (24px, one line) and 7xl (48px, two lines). Every other token is a fraction of a line. When a gap must stay on the raster, pass a line count to the Grid (gutter={1}) instead of a token.
Control rows (Button, Input, Select, and friends) take their padding from semantic aliases generated from the sizing presets, so the sizing pattern never carries a literal table. They are thin references to the scale above:
| token | value | description |
|---|---|---|
| control.padX.xs | {spacing.xs} | 8px |
| control.padX.sm | {spacing.sm} | 12px |
| control.padX.md | {spacing.md} | 16px |
| control.padX.lg | {spacing.xl} | 24px |
| control.padX.xl | {spacing.3xl} | 32px |
| control.padY.xs | {spacing.3xs} | 4px |
| control.padY.sm | {spacing.2xs} | 6px |
| control.padY.md | {spacing.xs} | 8px |
| control.padY.lg | {spacing.sm} | 12px |
| control.padY.xl | {spacing.md} | 16px |
<div
className={css({ paddingX: "control.padX.md", paddingY: "control.padY.md" })}
>
Aligns with a medium control
</div>
import { css } from "@pindoba/styled-system/css";
<div className={css({ padding: "md" })}>Uniform padding</div>
<div className={css({ paddingX: "lg", paddingY: "sm" })}>
Asymmetric padding
</div>
<div className={css({ marginX: "auto", marginY: "lg" })}>
Centered with vertical margin
</div>
<div className={css({ display: "flex", gap: "md" })}>
<div>Item 1</div>
<div>Item 2</div>
</div>
<div className={css({
display: "grid",
gridTemplateColumns: "repeat(3, 1fr)",
gap: "lg",
})}>
<div>Grid item</div>
<div>Grid item</div>
<div>Grid item</div>
</div>
<div
className={css({
padding: { base: "sm", md: "md", lg: "lg" },
})}
>
Responsive padding
</div>
5xs–2xs: Hairlines, icon gaps, compact elementsxs: Tight spacing between related elementssm: Close relationships, form field gapsmd: Standard spacing, comfortable defaultlg–xl: Generous spacing, component separation2xl–11xl: Major layout spacing, hero sectionswidth, height) use the sizes tokens