Skip to content

Core Concepts

Theme tokens

Your design decisions, as data.

A theme is a set of scales, and a scale is a set of named tokens.

ts
import { defineConfig } from "@croff/core";

export default defineConfig({
  theme: {
    colors: {
      accent: "#ff5c00",
      slate: { 100: "#f1f5f9", 900: "#0f172a" },
    },
    spacing: { 7: "1.75rem" },
  },
});

Using tokens

html
<div class="bg(accent) color(slate-100) padding(7)"></div>
Generated CSS
:root {
  --croff-color-accent: #ff5c00;
  --croff-color-slate-100: #f1f5f9;
  --croff-spacing-7: 1.75rem;
}

.padding\(7\) {
  padding: var(--croff-spacing-7);
}

.color\(slate-100\) {
  color: var(--croff-color-slate-100);
}

.bg\(accent\) {
  background-color: var(--croff-color-accent);
}

Nested groups flatten with hyphens, so slate: { 100: ... } is slate-100.

Built-in scales

ScaleUsed byCustom property
colorsbg, color, border-color and others--croff-color-*
spacingpadding, margin, gap, width and others--croff-spacing-*
radiusradius--croff-radius-*
fontsfont--croff-font-*
textSizestext-size--croff-text-size-*
textWeightstext-weight--croff-text-weight-*
lineHeightsline-height--croff-line-height-*
letterSpacingsletter-spacing--croff-letter-spacing-*
shadowsshadow--croff-shadow-*
durationsduration, transition--croff-duration-*
breakpointsResponsive variantsNone. Media queries can't read var().

Merging

Your theme merges over the default, token by token. null removes a token or a whole group, and preset: "none" starts from nothing. See Theme customization.

Validation

Token values are checked when the config loads. spacing: { 1: "wide" } fails, with a message saying what was expected, and so does any value that could break out of a CSS declaration. Using a token that doesn't exist is an error with a suggestion, not a silently empty rule.

Tokens at runtime

Tokens compile to custom properties, so you can override one in plain CSS, for a section or for a dark theme:

css
.campaign {
  --croff-color-brand: #ff5c00;
}