Skip to content

Utilities ​

A small set of unprefixed, Tailwind-like utility classes for composing layouts: display, flex-*, alignment, gap-*, position, inset-*, logical margin / padding, and text-* typography styles.

They are generated deterministically from the design tokens — the spacing scale comes straight from alias.space in tokens.json, so spacing utilities can never drift from the tokens. Add a space token, run npm run gen:utilities:css, and the matching classes appear.

html
<div class="flex flex-col gap-md items-start">
  <div class="flex justify-between items-center gap-sm">…</div>
</div>

Cascade ​

All utilities live in @layer utilities. Component styles (qs-button, qs-icon, …) are unlayered, and unlayered rules always beat layered ones — so a utility can never accidentally override a component's internals. Utilities are for the space between and around components, not for reaching inside them.

Display ​

flex · inline-flex · grid · inline-grid · block · inline-block · inline · hidden

Flexbox ​

Direction: flex-row · flex-row-reverse · flex-col · flex-col-reverse

Wrap: flex-wrap · flex-nowrap · flex-wrap-reverse

Grow / shrink: flex-1 · flex-auto · flex-initial · flex-none · grow · grow-0 · shrink · shrink-0

Alignment ​

Items: items-start · items-end · items-center · items-baseline · items-stretch

Justify: justify-start · justify-end · justify-center · justify-between · justify-around · justify-evenly

Content: content-start · content-end · content-center · content-between · content-around · content-evenly · content-stretch

Self: self-auto · self-start · self-end · self-center · self-stretch

Gap ​

gap-*, gap-x-* (column), gap-y-* (row). Each step maps to a spacing token:

Values are rem-based (relative), so they scale with the root font size.

ClassTokenValue
gap-0—0
gap-xs--space-xs0.25rem
gap-sm--space-sm0.5rem
gap-md--space-md1rem
gap-lg--space-lg1.5rem
gap-xl--space-xl2rem
gap-2xl--space-2xl3rem
gap-3xl--space-3xl4rem

Position ​

static · relative · absolute · fixed · sticky

Pinning: inset-0 · inset-x-0 (inline) · inset-y-0 (block)

Spacing (logical) ​

Margin and padding use logical properties, so they follow the writing direction:

PrefixProperty
m-* / p-*margin / padding (all sides)
mx-* / px-*margin-inline / padding-inline
my-* / py-*margin-block / padding-block
ms-* / ps-**-inline-start
me-* / pe-**-inline-end
mt-* / pt-**-block-start
mb-* / pb-**-block-end

Each accepts the same scale as gap (0, xs … 3xl), e.g. px-lg, my-sm, me-md.

Typography ​

One class per text style in component.text. Each property reads a --text-<style>-* token:

text-hero · text-display · text-large-title · text-headline · text-title · text-body · text-footnote · text-label · text-print · text-code

html
<h1 class="text-hero">Print.</h1>
<p class="text-body">Generous body copy at 17px.</p>

Accessibility ​

sr-only hides text visually but keeps it for screen readers. See visually hidden text.

html
<span class="sr-only">(opens in a new tab)</span>

Background patterns ​

Discreet surface patterns built on one grid: a module of --space-lg with a major line every 4 modules. Minor marks use --color-pattern (barely there), major lines --color-border, so every pattern lines up with the others and with the layout spacing. Each theme draws its own through its tokens: a 24px module in Editorial, a denser 16px module in Industrial. Put them on large, calm surfaces (page sections, empty states, hero panels), never behind body text you need to read closely.

ClassPattern
bg-gridminor grid every module, major grid every 4 modules
bg-dotsa dot at every module intersection, a stronger dot every 4
bg-linesbaseline rule every module, a stronger rule every 4 (scanlines in Industrial)
bg-grid
bg-dots
bg-lines
html
<section class="bg-grid">…</section>

Discreet movement ​

Add a motion modifier to a pattern. The pattern moves on a ::before layer with transform only (composited, off the main thread), and the loop moves exactly one major cell per cycle, so it never jumps. The settle variant plays when the element first appears; the showcase replays it each time you change the preview.

ModifierMotionRule
bg-drifteases one module over 5s (--duration-ambient-settle), then stays stillUse freely: it stops within 5 seconds (WCAG 2.2.2).
bg-drift-loopdrifts forever, one major cell (4 modules) per 24s (--duration-ambient-loop, linear)The page must offer a pause control that sets <html data-motion="paused">.

Both stop entirely under prefers-reduced-motion: reduce. A motion modifier makes the element position: relative, isolation: isolate and overflow: clip, so don't use it on an element that has popovers or menus spilling out of it.

bg-grid bg-drift
bg-dots bg-drift-loop
Pause or play background motion
html
<section class="bg-dots bg-drift-loop">…</section>
<button type="button" onclick="(d => d.dataset.motion ? delete d.dataset.motion : d.dataset.motion = 'paused')(document.documentElement)">
  Pause or play background motion
</button>

WebGPU showcase (docs only) ​

A CRT noise field for Industrial, drawn with Three.js TSL on a <canvas>: faint animated grain plus scanlines, in the current theme's --color-canvas and --color-text. It is a demo of what the token colours can drive, not part of the library: the CSS patterns above are what components and pages should use. It loops, so it has its own pause button and starts paused under reduced motion. Without WebGPU it falls back to WebGL 2, then to bg-lines.

Regenerating ​

bash
npm run gen:utilities:css

The extra spacing roles --space-2xs, --space-4xl, --space-5xl, --space-gutter and --space-margin are intentionally left out of the scale — use them directly via var(--space-gutter) when a layout calls for them.