Responsive, semantic spacing tokens for layout, section, and component rhythm.
Create UI ships a set of semantic spacing tokens. You write one class, such as gap-layout-xl, and it resolves to a different value at every breakpoint. The responsive curve lives inside the token, so you stop hand-tuning spacing per screen size and the whole product keeps a consistent rhythm.
There are 18 of them across three scales. Thirteen scale with the viewport and five hold one value on purpose.
One class, three values. The outlined panel is your screen right now, so resize the window and watch it move.
2 media queries in the system, 0 in your markupThe problem it solves
Responsive spacing usually means stacking breakpoint variants on every element. It is verbose, easy to get wrong, and impossible to change globally.
With tokens, the same intent is two classes:
The win is not just shorter class lists:
- One source of truth. The mobile, tablet, and desktop values are defined once per token. Every surface that uses
gap-layout-xlscales identically. - Global changes are one edit. Want page rhythm to feel tighter on tablet? You change the token, not hundreds of
md:variants spread across the codebase. - No drift. Designers and engineers reference the same named scale, so spacing stays on-system instead of becoming a pile of one-off
gap-7values.
The three scales
Spacing is split into three scales by what sits on either side of the gap. The bigger the things you are separating, the higher the scale.
Token reference
Each scale is drawn against its own largest step, so the steps within a scale compare directly and the card header says what a full track is worth. The head of each bar is the mobile value and each step after it is what the token gains as the screen grows, so the whole curve reads at a glance. Clicking a token name copies its gap-* class.
component-sm and component-xs are flat on purpose. Tight internal spacing reads the same at every screen size, so these tokens hold one value across all breakpoints.
Using the tokens
The token name plugs into any Tailwind spacing utility. Tailwind v4 generates the full set automatically, so all of these work:
The same applies to m-, mx-, my-, mt-, gap-x-, gap-y-, and the rest of the spacing utilities.
Prefer px-component-none over px-0 when you intentionally remove horizontal padding from a token-driven element. It keeps the intent explicit: this is a deliberate override of a semantic token, not an arbitrary zero.
Reading a token at runtime
The tokens reach your project as CSS custom properties, so Storybook, tests, and runtime logic read them off the document rather than importing a module.
The value you get back is the one for the current viewport, because the two max-width blocks have already resolved.
Choosing semantic vs raw spacing
Semantic tokens scale across breakpoints. That is exactly what you want when the design opts into responsive spacing, and exactly what you do not want for a fixed, static gap.
Use the token only when the design references one
Reach for a semantic class only when the design references a semantic spacing token (for example a Figma variable like component/sm). When the design specifies a static value (for example space-4), use the standard Tailwind class such as gap-4. Applying a semantic token to something meant to be static silently opts it into breakpoint scaling.
Real-world example
The three scales compose naturally: layout frames the section, section spaces the groups inside it, and component handles the internals of each card.
Resize the viewport and every gap retunes itself. You did not write a single breakpoint variant.
How it works
You do not need this to use the tokens, but it helps to know the numbers are generated, not hand-written.
The pipeline runs from a single data file to Tailwind utilities:
-
lib/createui-spacing.tsdefinesTOKENS. Responsive values use ther(mobile, tablet, desktop)helper; a single number means a flat value.lib/createui-spacing.ts -
registry/config.tsconsumes the tokens viabuildSpacingCssVars(), turning each into a responsive value string. -
The CLI splits each token across breakpoints, writing the desktop value to
:rootand the smaller values into the stylesheet's twomax-widthmedia queries.generated in app globals.css -
An
@theme inlineblock registers each--spacing-*variable, and Tailwind v4 auto-generates thegap-*,p-*,m-*utilities from it.
Changing or adding a token
Override the variable
Set the --spacing-* custom property in your own globals.css. Desktop goes on :root; the smaller ranges go in the two max-width blocks the CLI already wrote.
Register a brand-new name
Tailwind generates utilities only from names declared in @theme inline, and the CLI writes that block with the shipped tokens enumerated one by one. Overriding an existing token needs nothing more, but a new name has to be added:
Skip this and gap-section-2xl silently emits no rule at all.
Or pull the current scale
Re-running init rewrites the variables and media queries from the shipped tokens, which is the way to take an updated scale rather than keep a local edit.