createRecipe

createRecipe is a typed variant + state style resolver. It's the same system Reactnatively uses internally for all its components. Use it to build your own components that support variants, sizes, and interactive states — fully type-safe.

Concept

A recipe defines a component's style in terms of:

baseStyles shared by all instances, always applied.
variantsNamed style groups (e.g. solid, outline, ghost). Only one applies at a time.
sizesScale modifiers (e.g. sm, md, lg). Only one applies at a time.
statesModifier styles for interactive states: pressed, hovered, focused, disabled, loading, invalid.
defaultsFallback variant, size, and material when none is provided.

Basic usage

tagRecipe.ts
1import { createRecipe } from 'reactnatively/theme';23export type TagVariant = 'filled' | 'outline' | 'ghost';4export type TagSize   = 'sm' | 'md' | 'lg';56export const tagRecipe = createRecipe<TagVariant, TagSize>({7  base: {8    borderRadius: 6,9    alignItems: 'center',10    justifyContent: 'center',11    flexDirection: 'row',12    gap: 4,13  },14  variants: {15    filled:  { backgroundColor: '#6366f1' },16    outline: { borderWidth: 1, borderColor: '#6366f1' },17    ghost:   { backgroundColor: 'rgba(99,102,241,0.12)' },18  },19  sizes: {20    sm: { paddingHorizontal: 8,  paddingVertical: 3,  fontSize: 11 },21    md: { paddingHorizontal: 12, paddingVertical: 5,  fontSize: 13 },22    lg: { paddingHorizontal: 16, paddingVertical: 7,  fontSize: 15 },23  },24  states: {25    disabled: { opacity: 0.4 },26    pressed:  { opacity: 0.75 },27  },28  defaults: {29    variant: 'filled',30    size:    'md',31  },32});

Resolving the recipe

Tag.tsx
1import { tagRecipe, type TagVariant, type TagSize } from './tagRecipe';23interface TagProps {4  variant?: TagVariant;5  size?:    TagSize;6  disabled?: boolean;7  children: React.ReactNode;8}910export function Tag({ variant, size, disabled, children }: TagProps) {11  const resolved = tagRecipe({12    variant,13    size,14    states: disabled ? ['disabled'] : [],15  });1617  return (18    <Pressable style={resolved.style}>19      {children}20    </Pressable>21  );22}

extendRecipe

Extend an existing recipe without rewriting it — useful for brand-specific overrides on top of Reactnatively's built-in recipes:

typescript
import { extendRecipe } from 'reactnatively/theme';
import { tagRecipe } from './tagRecipe';

// Override just the filled variant colors
export const brandTagRecipe = extendRecipe(tagRecipe, {
  variants: {
    filled: { backgroundColor: '#e11d48' },   // brand red
  },
});

RecipeState values

StateTypical trigger
baseAlways applied (same as base style block)
pressedonPressIn active
hoveredPointer/hover active (web / pointer device)
focusedKeyboard focus active
selectedControlled selected state
disableddisabled prop is true
loadingloading prop is true
invalidForm validation error