Skip to content

Type to search the docs, API, and blog.

↑↓ navigate↵ openesc close
Zazz 0.7 alpha
API navigation

API

Style utilities

Values in style, one custom property per decision.

A style utility is a custom property in an element's style attribute: style="--p: 4; --w--md: fit-content". The rule is Tailwind's names, CSS values: a utility is named after the Tailwind class it stands in for (--justify, --items, --rounded), and it takes the value its CSS property takes (--justify: space-between, --w: 100%). If you know the property and not the class, look it up in the property-to-utility table.

The kit matches the attribute text, so spelling is exact: --<utility>: <value>, one space after the colon, declarations separated by ; .

Utilities 12 groups

Composed from atoms

No component class here — just flex, gap, padding, radius, border, shadow, and color utilities reading the same semantic tokens.

<article
  style="
    --display: flex-col;
    --p: 11;
    --gap: 6;
    --w: 100%;
    --max-w: 96;
    --text: var(--color-card-foreground);
    --bg: var(--color-card);
    --border-color: var(--color-border);
    --border-width: 1px;
    --shadow: md;
    --rounded: var(--radius-lg);
  "
>
  <div
    style="
      --display: flex;
      --items: center;
      --justify: space-between;
      --gap: 4;
    "
  >
    <span data-ui="badge" data-badge-variant="primary">Utilities</span>
    <span data-ui="text-xs" style="--text: var(--color-muted-foreground)">12 groups</span>
  </div>
  <hgroup
    style="
      --display: flex-col;
      --gap: 2;
    "
  >
    <h3 data-ui="text-lg" style="--font-family: var(--font-family-heading)">Composed from atoms</h3>
    <p
      data-ui="text-sm"
      style="
        --text-wrap: pretty;
        --text: var(--color-muted-foreground);
      "
    >
      No component class here — just flex, gap, padding, radius, border, shadow, and color utilities
      reading the same semantic tokens.
    </p>
  </hgroup>
  <div
    style="
      --display: flex;
      --items: center;
      --pt: 4;
      --gap: 4;
      --border-t: 1;
    "
  >
    <button type="button" data-ui="button" data-button-variant="primary">Get started</button>
    <button type="button" data-ui="button" data-button-variant="ghost">Browse groups</button>
  </div>
</article>

What a value can be

  • A scale number on spacing, margin, and sizing utilities: --px: 6 is 6 × --spacing. The space tokens sit on this scale (2xs 1, xs 2, sm 4, md 6, lg 11, xl 24, 2xl 40), so write the number and skip the var().
  • A length or any CSS value: --w: 100%, --rounded: var(--radius-lg), --shadow: 0 1px 2px black.
  • A token by name, on a few utilities, at every tier: --shadow: md, --font-weight: strong, --display: flex-col. The var() form (--shadow: var(--shadow-md)) always works too.
  • A keyword where the property takes one: --position: sticky, --w: fit-content, --grid-cols: subgrid.

One space after the colon

A tier gate reads the property itself, so --p:4 and --w--md:6 work with any spacing. A keyword (auto, subgrid), a token by name (md, strong), a --display shorthand, --bg: none, and --position: sticky are matched as text, and the text the kit looks for has one space after the colon. Written without it, --w:auto is 0 wide and --shadow:md draws nothing. The audit (<ui-debug>, the editor, and the ESLint plugin) reports both, and the formatter writes the space back.

The place this bites is a framework's object style: React and Vue serialize { "--w": "auto" } as --w:auto, and JSX is outside the linter. There, write those values as a string style, or in the var() form ("--shadow": "var(--shadow-md)").

Rules that bite

  1. A tier needs a base unless the utility works tier-only (the tables say which): write --text: currentColor; --text--hover: red, not --text--hover: red alone. Padding and --bg work tier-only on a plain element (--px--md: 8, --bg--hover: var(--color-muted)), since the reset leaves it unpadded and unpainted; where a primitive pads or paints the element itself, its value wins unless it reads the utility. --text, margin, and --font-size do not, because the base sets a link's color, the margins between text blocks, and a heading's size, and a tier-only value would reset them at rest.
  2. Breakpoints reach layout and color; states reach color and effects. --px--hover does not exist. The anchor utilities (--anchor-name, --position-anchor, --position-area) take both.
  3. A utility on a primitive flattens its states: --bg: red on a button is red on hover too. Add the state tier, or set the hook (--ui-button-bg) instead.
  4. Breakpoints read the nearest inline-size container, not the window. See breakpoints.

Every utility that writes a property is registered with @property as non-inheriting, so a value never leaks into a child; the --before-* / --after-* forms are the exception, read on the pseudo-element and never registered. Utilities live in @layer ui.utilities at zero specificity: they beat component rules by layer order, and any rule you write in overrides beats them.