Developer preview. Vela, Facet, and Quire are pre-release and in active development — syntax, APIs, and availability may change, and they are not yet generally available.
SStretch Dev Docs
Facet

Recipes in Depth

Define component variants that compile through the same atomizer as utilities and fx objects.

Recipes are Facet's component-variant authoring surface. They are defined as typed fx objects, then compiled through the same FIR and atomizer as utility strings and direct fx() calls.

The source example defines a button recipe:

// Component recipes (the 3rd authoring surface). Variants are typed fx objects that
// lower through the SAME atomizer, so recipe atoms dedup with utilities and fx().
import { defineRecipe } from "../src/fir.mjs";

export default {
  button: defineRecipe({
    base: { _focusVisible: { ring: true } },
    variants: {
      tone: {
        primary: { bg: "action", fg: "on-action", _hover: { bg: "action-hover" } },
        neutral: { bg: "surface", fg: "ink", _hover: { bg: "elevated" } },
        subtle: { bg: "bg", fg: "ink-muted" },
      },
      size: {
        sm: { px: "inset.md", py: "inset.sm", radius: "control" },
        md: { px: "inset.lg", py: "inset.md", radius: "control" },
      },
    },
    defaultVariants: { tone: "primary", size: "md" },
  }),
};

Parts of a recipe

  • base: styles that apply to every variant.
  • variants: enumerated axes. Each axis contains named values and each value is an fx object.
  • defaultVariants: the values used when a caller does not provide a prop.

The guide also shows compoundVariants support:

import { defineRecipe, registerRecipe } from "facet";
const button = registerRecipe(az, defineRecipe({
  base: { radius: "control", _focusVisible: { ring: true } },
  variants: { tone: { primary: { bg: "action", fg: "on-action" }, subtle: { bg: "bg", fg: "ink-muted" } },
              size:  { sm: { px: "inset.md", py: "inset.sm" }, lg: { px: "inset.lg", py: "inset.md" } } },
  compoundVariants: [ { when: { tone: "primary", size: "lg" }, style: { shadow: "card" } } ],
  defaultVariants: { tone: "primary", size: "lg" },
}));
button.classesFor({ tone: "primary", size: "lg" }); // -> "fc-... fc-... ..."

Dedup behavior

Recipes do not create a separate component CSS layer. Each declaration normalizes to the same canonical atom tuple used by utilities and fx():

{ prop: "<css-property>", value: "var(--token)", state: null, at: null }

That means tone.primary.bg = "action" can share an atom with:

<button class="bg-action fg-on-action radius-control px-inset-lg py-inset-md hover:bg-action-hover focus-visible:ring">
  Action
</button>

and with a direct fx() object:

{ bg: "action", fg: "on-action", radius: "control", px: "inset.lg", py: "inset.md",
  _hover: { bg: "action-hover" }, _focusVisible: { ring: true }, "@md": { px: "inset.lg" } }

Practical guidance

Use recipes where the variant list is finite and component-owned. Use utilities or fx() directly for one-off layout and local composition.

Because Facet is pre-release, treat the recipe API as reference implementation surface. The source spec confirms the concept and shape, while broader production parser coverage remains planned work.