Runtime
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.
Using Recipes in Components
Import your recipe function and call it with variant props to generate class names:
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:
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 Value | Runtime Value | Reason |
|---|---|---|
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:
- Starts with the recipe name as the base class (
button) - Adds all base declaration classes
- For each variant, uses the prop value or falls back to
defaultVariants - Resolves the variant option to its declaration classes
- Applies compound variants if all match conditions are satisfied
- Returns the combined class string
// 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:
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
Only if you use recipes. The @styleframe/runtime package provides the createRecipe function that powers runtime variant selection. If you're only using utilities, selectors, or themes, you don't need it.
The runtime package is automatically generated in virtual:styleframe when you define at least one recipe in your Styleframe configuration.
Recipes have minimal performance impact:
- Build time: CSS is generated statically, no runtime CSS generation
- Bundle size: The runtime is tree-shakeable and only includes what you use
- Runtime: Only string concatenation and object lookups, no DOM manipulation
The generated recipe functions are optimized to be as fast as possible while maintaining the full variant API.
Several ways to debug:
- Log the output: Call your recipe function and log the result to see the generated class string
- Inspect elements: Use browser DevTools to see which utility classes are applied
- Check generated CSS: Look at
styleframe/index.cssto see the generated utility classes - Review recipes.ts: Check the generated runtime to see how values are mapped
console.log(button({ color: "primary", size: "lg" }));
// → "button _border-width:thin _background:primary _padding:lg"
Overview
Styleframe recipes provide powerful component variants with type-safe configuration options. Create flexible, reusable UI components with consistent styling patterns and runtime variant selection.
Output Format
Learn how Styleframe recipes generate CSS utility classes, understand the connection between recipe fields and utilities, and master the class naming conventions.