apps/shade/src/docs/recipes-guide.mdx
import { Meta } from '@storybook/addon-docs/blocks';
<Meta title="Recipes / Recipes Guide" /> <div className="sb-doc">Canonical example: inputSurface. The border, background, radius, and focus ring shared by Input, Textarea, InputGroup, and the Select trigger.
React inside a recipe — that's a component.import {cn} from '@/lib/utils';
export const recipeClasses = {
base: '...',
stateA: '...',
stateB: '...'
} as const;
export function recipe(mode: 'a' | 'b' = 'a') {
return cn(recipeClasses.base, mode === 'a' ? recipeClasses.stateA : recipeClasses.stateB);
}
Function for the easy path, atoms (the as const object) for unusual cases where consumers need to compose a subset. Tokens everywhere underneath.
Full rules: Layers. Agent rules: apps/shade/AGENTS.md.
import {cn} from '@/lib/utils';
import {inputSurface, inputSurfaceClasses} from './input-surface';
// Common case — call the function
<input className={cn(inputSurface('self'), 'h-9 px-3 text-sm')} />
// Edge case — compose atoms statically so Tailwind can detect them
<div className={cn(
inputSurfaceClasses.base,
inputSurfaceClasses.invalidWithin
)} />
Browse the sidebar for the live list of recipes.
</div>