Skip to main content

Signature

// With context
function styled<T>(component: T, config: {
  context: StyledContext,
  base?: Props<T>,
  variants?: { [name: string]: { [value: string]: Props<T> } },
  defaultVariants?: { [name: string]: string | boolean },
  compoundVariants?: CompoundVariant[],
}): StyledComponent<T>

// Without context
function styled<T>(component: T, config: {
  base?: Props<T>,
  variants?: { [name: string]: { [value: string]: Props<T> } },
  defaultVariants?: { [name: string]: string | boolean },
  compoundVariants?: CompoundVariant[],
}): StyledComponent<T>

Parameters

component
ElementType
required
The base component to style. Can be:
  • HTML element string: "button", "div", "span"
  • React component: Link, Pressable
  • Another styled component
config
object
required
Configuration object with the following properties:

Config Properties

config.base
VariantProps<T>
Props that always apply, regardless of variants.
base: {
  className: "rounded-lg",
  role: "button",
}
config.variants
object
Variant definitions. Each key is a variant name, each value is an object mapping option names to props.
variants: {
  size: {
    sm: { className: "h-8" },
    md: { className: "h-10" },
    lg: { className: "h-12" },
  },
  color: {
    blue: { className: "bg-blue-500" },
    red: { className: "bg-red-500" },
  },
}
When using context, variants defined here but not in createStyledContext() become local variants. They work on this component but don’t propagate to children. See Local Variants.
config.defaultVariants
object
Default values for variants when not specified.
defaultVariants: {
  size: "md",
  color: "blue",
}
config.compoundVariants
array
Array of compound variant definitions. Each applies when all conditions match.
compoundVariants: [
  {
    size: "lg",
    color: "blue",
    props: { className: "shadow-lg" },
  },
]
config.context
StyledContext
Context for variant propagation between parent and child components.
const ButtonContext = createStyledContext({ ... });

styled("button", {
  context: ButtonContext,
  // ...
});

Returns

A React component with:
  • All props from the base component
  • Variant props based on your config
  • Automatic type inference

Examples

Basic

import { styled } from "better-styled";

const Button = styled("button", {
  base: { className: "px-4 py-2 rounded font-medium" },
  variants: {
    variant: {
      primary: { className: "bg-blue-600 text-white" },
      secondary: { className: "bg-gray-200 text-gray-900" },
    },
  },
  defaultVariants: {
    variant: "primary",
  },
});

<Button variant="secondary">Click me</Button>

With Context

const ButtonContext = createStyledContext({
  size: ["sm", "md", "lg"],
});

const Button = styled("button", {
  context: ButtonContext,
  variants: {
    size: {
      sm: { className: "text-sm" },
      md: { className: "text-base" },
      lg: { className: "text-lg" },
    },
  },
});

With React Native

import { Pressable } from "react-native";

const Button = styled(Pressable, {
  base: { className: "rounded-lg px-4 py-2" },
  variants: {
    isDisabled: {
      true: { className: "opacity-50", disabled: true },
    },
  },
});
⚠️ Use isDisabled instead of disabled to avoid shadowing Pressable’s native prop.

Boolean Variants

const Input = styled("input", {
  variants: {
    hasError: {
      true: { className: "border-red-500" },
    },
  },
});

<Input hasError />
<Input hasError={false} />
You only need to define true. The false case uses base styles by default.

Compound Variants

const Badge = styled("span", {
  variants: {
    size: { sm: {}, lg: {} },
    color: { blue: {}, red: {} },
  },
  compoundVariants: [
    {
      size: "lg",
      color: "blue",
      props: { className: "ring-2 ring-blue-300" },
    },
    {
      size: "lg",
      color: "red",
      props: { className: "ring-2 ring-red-300" },
    },
  ],
});

Props Merging Behavior

Prop TypeMerge Behavior
className🔀 Merged with tailwind-merge
style🔀 Object merged with Object.assign
Functions (onClick, etc.)⛓️ Composed (all execute)
Other props⬆️ Later values override
Priority order (lowest to highest):
  1. 🥉 base
  2. 🥈 variants
  3. 🥈 compoundVariants
  4. 🥇 Direct props

See Also