refract v0.1 · beta
Subsystems / Components

Components

The payoff: a component recipe is pure composition — it references a colours + typography + layout + effects + borders recipe and adds its own delta.

raw slice components.recipes
live render hover / disabled
refracted · the point: a component recipe is pure composition — it references a colors + typography + layout + effects recipe and adds an own css delta. The chip row under each control is its real classList (own delta outlined).

Overview

The components subsystem is closed and recipes-only — it owns no primitive properties and emits no tokens; the property pipeline never runs for it. A component recipe is pure composition: it references other subsystems' recipes and adds its own css delta. This is where every other subsystem lands together.

How composition works

A component variant names a recipe from one or more subsystems by that subsystem's key, and optionally adds its own css delta. refract resolves it to a class list: the referenced recipe classes (which carry their own :hover etc. on their shared class) followed by the component's own delta class (dt-components-<group>-<variant>). Read it from theme.classes.components.<group>.<variant>.

The css delta is literal-first — it's raw CSS. A bare string or number is a literal (cursor: "pointer", gap: 8); a token reference uses the ref() helper (color: ref("colors.brand.text")var(--dt-colors-brand-text)) or the JSON-safe { ref: "…" } object. This differs from the composition fields above (colors: "solid.brand"), where a bare string is always a reference — those compose tokens, the css block writes CSS. A ref() at an unknown token is a build error. Because a literal css value passes through verbatim, sanitize it before serving output built from an untrusted theme — see the FAQ.
PropTypeDescription
colorsstringA colors recipe ref — e.g. "solid.brand".
typographystringA typography recipe ref — e.g. "button.base".
layoutstringA layout recipe ref — e.g. "padding.button".
effectsstringAn effects recipe ref — e.g. "surface.card".
<subsystem>stringAny subsystem key → its <group>.<variant> recipe (e.g. animation: "motion.enter").
cssRecord<string, CssDeltaValue>The own CSS delta rendered on the dt-components-… class. Literal-first (see the note above): a bare string / number is a raw literal, and ref("…") / { ref: "…" } is a token reference → var(--…).
statesStateEntry[]Own-delta state overrides — a list of { state, target?, … }; each carries a css block (e.g. { state: "hover", css: {…} }). Optional target scopes onto a variant sibling.
responsiveResponsiveEntry[]Own-delta @media overrides; each carries a css block.

The resolved class

theme.classes.components.<group>.<variant> returns a ResolvedComponentClass:

FieldTypeDescription
classNamestringThe space-joined class list — referenced recipe classes, then the own delta class. Apply this directly.
classListstring[]The same list as an array.

The referenced recipes' own states ride along on their shared classes — a button carrying dt-colors-solid-brand gets that recipe's :hover for free. The component adds its own states on its delta class; both apply, and the delta wins at equal specificity by later source order. For precedence that doesn't depend on load order, emit into a cascade layer.

components.recipes.ts
components.recipes: {
  buttons: {
    primary: {
      colors: "solid.brand", typography: "button.base",
      layout: "padding.button", effects: "surface.focusable",
      css: { color: ref("colors.brand.text"), cursor: "pointer", border: "none", display: "inline-flex", gap: "8px" },
      states: [{ state: "hover", css: { transform: "translateY(-1px)" } }],
    },
    ghost: { colors: "outline.brand", typography: "button.base", layout: "padding.button",
             css: { background: "transparent" } },
  },
  cards:  { default: { effects: "surface.card", layout: "padding.card", typography: "body.base",
                       css: { display: "flex", flexDirection: "column", gap: "10px" } } },
  badges: { accent:  { colors: "solid.accent", typography: "label.caps",
                       css: { display: "inline-flex", borderRadius: "9999px" } } },
}
app.ts · the resolved class
theme.classes.components.buttons.primary
// → {
//   className: "dt-colors-solid-brand dt-typography-button-base dt-layout-padding-button
//               dt-effects-surface-focusable dt-components-buttons-primary",
//   classList: [ …the five classes… ],
// }
button.className = theme.classes.components.buttons.primary.className;
dist/theme.css · emitted
/* the component emits ONLY its own delta class + own states … */
.dt-components-buttons-primary {
  color: var(--dt-colors-brand-text);   /* "colors.brand.text" ref → var */
  cursor: pointer; border: none; display: inline-flex; gap: 8px;
}
.dt-components-buttons-primary:hover { transform: translateY(-1px); }

/* … the referenced classes bring their own rules & states: */
.dt-colors-solid-brand { background: var(--dt-colors-brand); color: var(--dt-colors-brand-text); }
.dt-colors-solid-brand:hover { background: var(--dt-colors-brand-dark); }
.dt-typography-button-base { /* … */ }
.dt-layout-padding-button { /* … */ }
.dt-effects-surface-focusable { /* … */ }
Technical documentation for @theme-registry/refract · all output is compiled client-side by the real library (CSS adapter). The chrome is theme-aware; the render panes carry each preset's own world. · MIT licensed.