Skip to main content

Basic Syntax

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"
    }
  }
})

const Button = buttonStyles(ButtonPrimitive)

Style Configuration

The style configuration object supports five main properties:

Base - Foundation styles

Classes applied to all instances of the component. Each key accepts a string of classnames or an array of classname strings for better readability:
base: "px-4 py-2 rounded font-medium transition-colors"
Or as an array for better readability with long classname lists:
base: [
  "px-4 py-2 rounded font-medium",
  "transition-colors hover:bg-gray-100",
  "focus:outline-none focus:ring-2 focus:ring-blue-500"
]
Can also be an object for complex components:
base: {
  root: "rounded-lg border bg-white",
  header: "px-6 py-4 border-b",
  content: "px-6 py-4"
}

Variants - Mutually exclusive options

Different visual styles (only one can be active):
variants: {
  variant: {
    default: "bg-primary text-primary-foreground",
    secondary: "bg-secondary text-secondary-foreground"
  },
  size: {
    sm: "h-9 px-3 text-sm",
    lg: "h-11 px-8 text-base"
  }
}

Modifiers - Boolean flags

Styles that can be combined:
modifiers: {
  disabled: "opacity-50 cursor-not-allowed",
  loading: "cursor-wait",
  fullWidth: "w-full"
}

Defaults - Reduce repetition

Set default values for variants:
defaults: {
  variants: { variant: "default", size: "default" }
}

Conditionals - Advanced logic

Apply styles only when specific conditions are met:
conditionals: [
  {
    variants: { variant: "default" },
    modifiers: ["loading"],
    className: "bg-primary/70"
  }
]

What You Get Back

The recast.styles() function returns a style object with two key capabilities:

1. Component Application

Apply styles to any React component:
const Button = buttonStyles(ButtonPrimitive)
const Link = buttonStyles('a') // Works with HTML elements too

2. Style Extraction

Extract computed class names for advanced use cases:
const classes = buttonStyles.extract({ 
  variant: "default", 
  size: "lg",
  disabled: true 
})
// Returns: "inline-flex items-center justify-center rounded-md text-sm font-medium bg-primary text-primary-foreground h-11 px-8 opacity-50 cursor-not-allowed"
Use extraction for: Server-side rendering, integration with animation libraries, or when you need raw class names.

Simple vs Complex Components

Simple Components (String Base)

For single-element components, use a string base:
import { recast } from '@rpxl/recast'

export const buttonStyles = recast.styles({
  base: "inline-flex items-center justify-center rounded-md text-sm font-medium",
  variants: {
    variant: {
      default: "bg-primary text-primary-foreground",
      secondary: "bg-secondary text-secondary-foreground"
    }
  }
})

Complex Components (Object Base)

For multi-element components, use an object base:
import { recast } from '@rpxl/recast'

export const cardStyles = recast.styles({
  base: {
    root: "rounded-lg border bg-card text-card-foreground shadow-sm",
    header: "flex flex-col space-y-1.5 p-6",
    title: "text-2xl font-semibold leading-none tracking-tight",
    content: "p-6 pt-0"
  },
  variants: {
    size: {
      sm: {
        header: "p-4",
        content: "p-4 pt-0"
      }
    }
  }
})

Performance

Recast automatically optimizes style computation:
  • Memoization: Results are cached to avoid recomputation
  • LRU Cache: Prevents memory leaks in long-running applications
  • Fast Extraction: Style extraction is optimized for performance
Performance Example
// First call - computed and cached
const classes1 = buttonStyles.extract({ variant: "default" })

// Second call - returns cached result instantly  
const classes2 = buttonStyles.extract({ variant: "default" })

// Only different combinations trigger new computations
const classes3 = buttonStyles.extract({ variant: "secondary" })
Performance Tip: Create style objects outside of components, not inside render functions. This ensures styles are created once and reused.

Best Practices

Create Once

Define style objects outside components to avoid recreation on every render

Use Defaults

Set sensible defaults to reduce prop repetition in your components

Semantic Names

Use meaningful variant names like variant and size.

Composition Ready

Design styles to work well with recast.compose() for maximum reusability