Recipes

Runtime

Learn how to use Styleframe recipes in your components with the runtime package. Understand how variant resolution works and how to integrate recipes into your React, Vue, or other framework components.

Once defined, recipes are generated as functions that you can import and use in your components. The runtime package provides lightweight functions that power recipe variant selection.

Important: Styleframe generates static CSS by default with zero runtime overhead. The TypeScript runtime package is only generated if you use recipes for dynamic variant selection.

Using Recipes in Components

Import your recipe function and call it with variant props to generate class names:

src/components/Button.tsx
import { button } from "virtual:styleframe";

function Button({ color, size, children, ...props }) {
    // Generate class names based on variant props
    const className = button({ color, size });
    // Returns: "button _border-width:thin _border-style:[solid] _background:primary _color:white _padding:md"

    return (
        <button className={className} {...props}>
            {children}
        </button>
    );
}

export default Button;

Generated Runtime Code

When you define a recipe, Styleframe auto-generates a TypeScript file with a runtime representation of your recipe. Here's what the generated code looks like:

recipes.ts (auto-generated)
import { createRecipe } from "@styleframe/runtime";
import type { RecipeRuntime } from "@styleframe/runtime";

const buttonRecipe = {
    base: {
        borderWidth: "thin",
        borderStyle: "[solid]",
    },
    variants: {
        color: {
            primary: {
                background: "primary",
                color: "white",
            },
            secondary: {
                background: "secondary",
                color: "white",
            },
        },
        size: {
            sm: { padding: "sm" },
            md: { padding: "md" },
            lg: { padding: "lg" },
        },
    },
    defaultVariants: {
        color: "primary",
        size: "md",
    },
} as const satisfies RecipeRuntime;

export const button = createRecipe("button", buttonRecipe);

Runtime Values vs Config Values

Notice how the runtime recipe stores simplified values compared to your config:

Config ValueRuntime ValueReason
ref(colorPrimary)"primary"Token path simplified
"@border-width.thin""thin"Token name extracted
"solid""[solid]"Arbitrary value wrapped

This keeps the runtime code minimal while preserving all information needed to generate class names.

How Runtime Resolution Works

The runtime function:

  1. Starts with the recipe name as the base class (button)
  2. Adds all base declaration classes
  3. For each variant, uses the prop value or falls back to defaultVariants
  4. Resolves the variant option to its declaration classes
  5. Applies compound variants if all match conditions are satisfied
  6. Returns the combined class string
Example
// With defaultVariants: { color: "primary", size: "md" }

button({})
// Output: "button _border-width:thin _border-style:[solid] _background:primary _color:white _padding:md"

button({ color: "secondary" })
// Output: "button _border-width:thin _border-style:[solid] _background:secondary _color:white _padding:md"

button({ color: "secondary", size: "lg" })
// Output: "button _border-width:thin _border-style:[solid] _background:secondary _color:white _padding:lg"

Type Safety

Recipe functions are fully typed based on your variant definitions. TypeScript will autocomplete variant names and values, and catch invalid combinations at compile time:

src/components/Button.tsx
import { button } from "virtual:styleframe";

// ✅ Valid - TypeScript knows these are valid variants
button({ color: "primary", size: "lg" })

// ❌ Error - TypeScript catches invalid variant values
button({ color: "invalid" })
//              ^^^^^^^^^ Type '"invalid"' is not assignable to type '"primary" | "secondary"'

Frequently Asked Questions