zfb
GitHub repository

Type to search...

to open search from anywhere

Tokens

Define the project supplied values used by zudo-wind utility families.

Name the values your project owns

Put named values under the root wind.tokens object. For example, spacing: { "hsp-sm": "0.75rem", "vsp-md": "1.25rem" } gives px-hsp-sm and py-vsp-md; colors: { "surface": "#f4f1ec", "ink": "#203046" } gives bg-surface and text-ink. These are complete class candidates. No custom-property declaration is needed for these literal values; Wind emits --zw-spacing-hsp-sm, --zw-spacing-vsp-md, --zw-color-surface, and --zw-color-ink from the configuration. See the copyable quickstart.

Optional numeric spacing unit

Nonzero numeric spacing is an explicit opt-in. Set wind.tokens.spacingUnit if your project wants classes such as p-4; with "0.25rem", p-4 means 1rem. This is not a built-in Tailwind scale. The preview compares a numeric value with a named token. It explicitly configures both:

Compare numeric and named spacing
HTML
<div class="wind-demo-grid grid grid-cols-2 gap-4">
  <div class="wind-demo-card bg-panel text-ink p-4 rounded-card">p-4 uses the configured spacing unit.</div>
  <div class="wind-demo-card bg-panel text-ink p-card rounded-card">p-card uses the named spacing token.</div>
</div>
CSS
@layer zw-reset, zw-tokens, zfb-hi, base, components;
@layer zw-tokens {
  :root {
    --zw-color-ink: #203046;
    --zw-color-panel: #f4f1ec;
    --zw-radius-card: .5rem;
    --zw-spacing-card: 1.5rem;
    --zw-spacing-unit: .25rem;
  }
}
.wind-demo-grid {
  font: 14px / 1.5 system-ui, sans-serif;
}

.wind-demo-card {
  border: 1px solid #8797aa;
  min-height: 4rem;
}
.grid {
  display: grid;
}
.grid-cols-2 {
  grid-template-columns: repeat(2,minmax(0,1fr));
}
.p-4 {
  padding-top: 1rem;
  padding-right: 1rem;
  padding-bottom: 1rem;
  padding-left: 1rem;
}
.p-card {
  padding-top: var(--zw-spacing-card);
  padding-right: var(--zw-spacing-card);
  padding-bottom: var(--zw-spacing-card);
  padding-left: var(--zw-spacing-card);
}
.gap-4 {
  column-gap: 1rem;
  row-gap: 1rem;
}
.text-ink {
  color: var(--zw-color-ink);
}
.bg-panel {
  background-color: var(--zw-color-panel);
}
.rounded-card {
  border-top-left-radius: var(--zw-radius-card);
  border-top-right-radius: var(--zw-radius-card);
  border-bottom-right-radius: var(--zw-radius-card);
  border-bottom-left-radius: var(--zw-radius-card);
}
Configuration for this example
{
  "wind": {
    "spec": 1,
    "reset": "none",
    "strict": true,
    "tokens": {
      "spacingUnit": "0.25rem",
      "spacing": {
        "card": "1.5rem"
      },
      "colors": {
        "panel": "#f4f1ec",
        "ink": "#203046"
      },
      "radii": {
        "card": "0.5rem"
      }
    },
    "breakpoints": {},
    "defaultTransitionTimingFunction": "ease",
    "authoredClasses": {
      "wind-demo-grid": true,
      "wind-demo-card": true
    },
    "safelist": {
      "docs-preview": [
        "grid",
        "grid-cols-2",
        "gap-4",
        "bg-panel",
        "text-ink",
        "p-4",
        "p-card",
        "rounded-card"
      ]
    }
  }
}
Authored demonstration CSS
.wind-demo-grid { font: 14px/1.5 system-ui, sans-serif; }
.wind-demo-card { border: 1px solid #8797aa; min-height: 4rem; }

Without a spacing unit, nonzero numeric spacing reports ZW006 instead of assuming a framework default.

<div class="p-4">p-4 needs a configured spacingUnit.</div>

Expected diagnostics: ZW006 (error)

Configuration for this example
{
  "wind": {
    "spec": 1,
    "reset": "none",
    "strict": true,
    "tokens": {},
    "breakpoints": {},
    "defaultTransitionTimingFunction": "ease",
    "authoredClasses": {},
    "safelist": {
      "docs-preview": [
        "p-4"
      ]
    }
  }
}
Authored demonstration CSS

See the configuration guide for the full schema and the utility index for every token-backed utility.

Token names, validation, and emitted variables

No implicit theme

V1 ships no color palette, spacing unit, named scale, breakpoint, font family, font weight, radius, shadow, or named easing token. Transition utilities use ease as their default timing function; set wind.defaultTransitionTimingFunction to choose another project default. The values 0, px, and the closed catalog's static keywords are language constants; they are not theme entries. Add every project-specific token value to wind.tokens.

A token map contains data, not executable code. The available categories and their emitted custom-property prefixes are:

Config fieldEmitted prefixUtility use
colors--zw-color-Text color, background color, border, divide, outline, and accent values
spacing--zw-spacing-Named spacing and eligible sizing values
sizes--zw-size-Named width, height, and size values
fontSizes--zw-font-size-Text size, with optional paired leading
fontFamilies--zw-font-family-Font family
fontWeights--zw-font-weight-Font weight
lineHeights--zw-leading-Line height
letterSpacings--zw-tracking-Letter spacing
radii--zw-radius-Border radius
shadows--zw-shadow-Box shadow
zIndices--zw-z-Z index
easings--zw-ease-Transition timing function

The separate spacingUnit field emits --zw-spacing-unit. Breakpoints and dark-mode settings affect variants; they do not create token variables. Every configured token is emitted, even when no candidate currently uses it. Names and variables are ordered by category and token name.

tokens.easings supplies named values for explicit ease-* utilities. The project-wide timing used by transition utilities is configured separately with wind.defaultTransitionTimingFunction; its default is ease, and it accepts a CSS timing function value rather than a token name. An explicit ease-* utility overrides that default in the same variant bucket.

Font sizes

Configure each font-size token as an object with a required size and optional lineHeight:

fontSizes: {
  sm: { size: "0.875rem", lineHeight: "1.25rem" },
  caption: { size: "0.75rem" }
}

This emits --zw-font-size-sm, --zw-font-size-sm-leading, and --zw-font-size-caption. The text-sm utility emits font-size and line-height; text-caption emits only font-size because that token has no lineHeight.

Names and lookup rules

Names use lowercase ASCII letters and digits, with single hyphens between alphanumeric segments. Names must start and end with an alphanumeric character. Numeric components are allowed, so neutral-50 and 2xl are valid. Uppercase DEFAULT is rejected; use lowercase default where the category allows it.

default is reserved for radii and shadows, where it supplies bare rounded and shadow. It also supports explicit rounded-default and shadow-default. A color or spacing map cannot use it as a general fallback. Keys that collide with numeric suffixes, fixed keywords, or a reserved family name are rejected rather than shadowing the language.

Some utility roots share lookup namespaces:

  • spacing and sizes names must be disjoint for sizing utilities.

  • colors and fontSizes names must be disjoint for text-*.

  • fontFamilies and fontWeights names must be disjoint for font-*.

For example, adding the same key to colors and fontSizes makes that binding ambiguous. Resolve the collision by choosing distinct names.

Spacing and numeric values

spacingUnit is a single nonnegative CSS dimension or zero. It cannot be a percentage, calc(), or var(). Nonzero numeric spacing is unavailable when the unit is missing; a configured zero unit is valid and makes numeric multiples zero. With a unit of 0.25rem, p-4 is calculated exactly as four times that unit; p-1.5 produces 0.375rem. Decimal multiplication uses decimal digits rather than floating point, with an 18-significant-digit limit on inputs and results. Zero and the unit constant px remain available without a configured scale.

Named entries in spacing are used directly through a custom property. Numeric values and named values are distinct forms. Sizing roots also consult sizes, then spacing, while the token names for both maps must remain disjoint. A CSS fraction such as w-1/2 is a separate sizing form; its slash never means color opacity.

Breakpoints are configured separately as positive integer pixel widths. For example, sm: ... requires a configured sm entry; the configuration supplies minWidthPx. Breakpoint widths are compared numerically, not by their names, and duplicate widths fail validation.

Validating values

Each token value is checked with the CSS parser for the property that consumes it. Examples include color for colors, padding length for spacing, width for sizes, font size for fontSizes, and border radius for radii. Radius entries must be a single nonnegative length-percentage. Z-index entries are integer strings or var() references: for example, use zIndices: { content: "10" }; a JSON or TypeScript number such as zIndices: { content: 10 } is rejected with invalid type: integer ..., expected a string. A bare string in fontSizes is rejected with wind.tokens.fontSizes entries are objects; write { size: "<value>" } (optionally with lineHeight) instead of the bare string "<value>"; other shapes are rejected with expected an object { size: string, lineHeight?: string }. Easing entries must be a single timing function or keyword.

External custom properties may appear in values for categories other than spacingUnit. If the CSS parser cannot prove the property's type because the value references var(), the binding is marked category-unverified and exposed by zfb wind explain; zfb does not verify the variable's type at runtime. The whole value must still parse, and its parts outside var() must fit the property, so a token and an arbitrary value with the same spelling are accepted or rejected alike; semicolons, braces, !important, URL functions, and keywords such as inherit or revert are rejected. Token values cannot reference the reserved --zw- namespace. Point a token at a project property and override that project property in authored CSS instead.

Emitted variables

All configured values are exposed under the --zw- namespace inside @layer zw-tokens. The category-to-prefix table gives the exact mapping, including fontSizes values under --zw-font-size- and a paired -leading variable when configured. The font-size token key cannot itself end in -leading, because that name is reserved for the paired value. No theme namespace is wiped from authored CSS; Tailwind's default namespace is simply not provided (see Default theme variables). Token values are not substituted inline; a project may override the generated custom properties in authored CSS.

See also

Revision History

CreatedUpdated