Recipes

Create multi-variant styles with a type-safe runtime API, heavily inspired by Stitches.

As with the rest of vanilla-extract, all styles are generated at build time.

💡 Recipes is an optional package built on top of vanilla-extract using its function serialization API. It doesn’t have privileged access to vanilla-extract internals so you’re also free to build alternative implementations.

Setup

npm install @vanilla-extract/recipes

recipe

Creates a multi-variant style function that can be used at runtime or statically in .css.ts files.

Accepts an optional set of base styles, variants, compoundVariants and defaultVariants.

button.css.ts
import { recipe } from '@vanilla-extract/recipes';

export const button = recipe({
  base: {
    borderRadius: 6
  },

  variants: {
    color: {
      neutral: { background: 'whitesmoke' },
      brand: { background: 'blueviolet' },
      accent: { background: 'slateblue' }
    },
    size: {
      small: { padding: 12 },
      medium: { padding: 16 },
      large: { padding: 24 }
    },
    rounded: {
      true: { borderRadius: 999 }
    }
  },

  // Applied when multiple variants are set at once
  compoundVariants: [
    {
      variants: {
        color: 'neutral',
        size: 'large'
      },
      style: {
        background: 'ghostwhite'
      }
    }
  ],

  defaultVariants: {
    color: 'accent',
    size: 'medium'
  }
});
CSS
.button_button__708odg0 {
  border-radius: 6px;
}
.button_button_color_neutral__708odg1 {
  background: whitesmoke;
}
.button_button_color_brand__708odg2 {
  background: blueviolet;
}
.button_button_color_accent__708odg3 {
  background: slateblue;
}
.button_button_size_small__708odg4 {
  padding: 12px;
}
.button_button_size_medium__708odg5 {
  padding: 16px;
}
.button_button_size_large__708odg6 {
  padding: 24px;
}
.button_button_rounded_true__708odg7 {
  border-radius: 999px;
}
.button_button_compound_0__708odg8 {
  background: ghostwhite;
}

With this recipe configured, you can now use it in your templates.

app.ts
import { button } from './button.css.ts'; document.write(` <button class="${button({ color: 'accent', size: 'large', rounded: true })}"> Hello world </button> `);

Your recipe configuration can also make use of existing variables, classes and styles.

For example, you can pass in the result of your sprinkles function directly.

button.css.ts
import { recipe } from '@vanilla-extract/recipes'; import { reset } from './reset.css.ts'; import { sprinkles } from './sprinkles.css.ts'; export const button = recipe({ base: [reset, sprinkles({ borderRadius: 'round' })], variants: { color: { neutral: sprinkles({ background: 'neutral' }), brand: sprinkles({ background: 'brand' }), accent: sprinkles({ background: 'accent' }) }, size: { small: sprinkles({ padding: 'small' }), medium: sprinkles({ padding: 'medium' }), large: sprinkles({ padding: 'large' }) } }, defaultVariants: { color: 'accent', size: 'medium' } });

RecipeVariants

A utility to make use of the recipe’s type interface. This can be useful when typing functions or component props that need to accept recipe values as part of their interface.

button.css.ts
import { recipe, RecipeVariants } from '@vanilla-extract/recipes'; export const button = recipe({ variants: { color: { neutral: { background: 'whitesmoke' }, brand: { background: 'blueviolet' }, accent: { background: 'slateblue' } }, size: { small: { padding: 12 }, medium: { padding: 16 }, large: { padding: 24 } } } }); // Get the type export type ButtonVariants = RecipeVariants<typeof button>; // the above will result in a type equivalent to: export type ButtonVariants = { color?: 'neutral' | 'brand' | 'accent'; size?: 'small' | 'medium' | 'large'; };