Skip to main content

Variants

Variants are mutually exclusive styling options. Only one value from each variant group can be active at a time.
const buttonStyles = recast.styles({
  base: "px-4 py-2 rounded font-medium",
  variants: {
    variant: {
      primary: "bg-blue-500 text-white",
      secondary: "bg-gray-200 text-gray-900"
    },
    size: {
      sm: "px-3 py-1 text-sm",
      md: "px-4 py-2",
      lg: "px-6 py-3 text-lg"
    }
  }
})

const Button = buttonStyles(ButtonPrimitive)
Think of variants like radio buttons - you can only select one option from each group.

Common Variant Patterns

variant: {
  primary: "bg-blue-500 text-white",
  secondary: "bg-gray-200 text-gray-900", 
  danger: "bg-red-500 text-white"
}
size: {
  sm: "h-8 px-3 text-sm",
  md: "h-9 px-4 py-2", 
  lg: "h-10 px-6 text-lg"
}

Modifiers

Modifiers are boolean-based styles that can be combined. Multiple modifiers can be active simultaneously.
const buttonStyles = recast.styles({
  base: "px-4 py-2 rounded font-medium",
  modifiers: {
    disabled: "opacity-50 cursor-not-allowed",
    loading: "cursor-wait",
    fullWidth: "w-full",
    elevated: "shadow-lg"
  }
})
Think of modifiers like checkboxes - you can combine multiple flags together.

Common Modifier Patterns

modifiers: {
  disabled: "opacity-50 cursor-not-allowed",
  loading: "cursor-wait animate-pulse",
  active: "ring-2 ring-blue-500"
}
modifiers: {
  fullWidth: "w-full",
  centered: "mx-auto",
  elevated: "shadow-lg"
}

Combining Variants & Modifiers

The power of Recast comes from combining variants and modifiers:
Complete Example
const buttonStyles = recast.styles({
  base: "inline-flex items-center justify-center rounded font-medium transition-colors",
  variants: {
    variant: {
      primary: "bg-blue-500 text-white hover:bg-blue-600",
      secondary: "bg-gray-200 text-gray-900 hover:bg-gray-300"
    },
    size: {
      sm: "h-8 px-3 text-sm",
      md: "h-9 px-4 py-2",
      lg: "h-10 px-6 text-lg"
    }
  },
  modifiers: {
    disabled: "opacity-50 cursor-not-allowed",
    fullWidth: "w-full",
    loading: "cursor-wait"
  },
  defaults: {
    variants: { variant: "primary", size: "md" }
  }
})

const Button = buttonStyles(ButtonPrimitive)
// Uses defaults: variant="primary" size="md"
<Button>Default Button</Button>

// Override variants, add modifiers
<Button variant="secondary" size="lg" fullWidth disabled>
  Large Secondary Full-Width Disabled Button
</Button>

// Multiple modifiers
<Button loading fullWidth>
  Loading Full-Width Button
</Button>

Default Values

Set default values to reduce repetition:
const buttonStyles = recast.styles({
  variants: {
    variant: { primary: "...", secondary: "..." },
    size: { sm: "...", md: "...", lg: "..." }
  },
  defaults: {
    variants: { variant: "primary", size: "md" }
  }
})

// These are equivalent:
<Button>Click me</Button>
<Button variant="primary" size="md">Click me</Button>
Key Takeaway: Use variants for mutually exclusive options (like colors or sizes) and modifiers for combinable flags (like states or layout properties).