API Reference
Complete API reference for styled-cva exports, methods, and TypeScript utilities.
tw
The main export from @styled-cva/react. It's a function that can be used to create styled components.
Basic Usage
import tw from "@styled-cva/react";
const Button = tw.button`bg-blue-500 text-white`;With Element Types
You can use tw with any HTML element:
const Div = tw.div`container mx-auto`;
const Input = tw.input`border rounded`;
const A = tw.a`text-blue-500 hover:underline`;With Custom Components
You can also wrap custom components:
import MyComponent from "./MyComponent";
const StyledComponent = tw(MyComponent)`bg-gray-100 p-4`;Extending Styled Components
You can extend existing styled components to add additional styles:
const BaseButton = tw.button`btn-base`;
// Extend with additional classes
const ExtendedButton = tw(BaseButton)`bg-green-500 hover:bg-green-600`;
// This works with CVA components too
const VariantButton = tw.button("btn-base", {
variants: {
$variant: {
primary: "btn-primary",
secondary: "btn-secondary",
},
},
});
const ExtendedVariantButton = tw(VariantButton)`rounded-lg`;.cva()
Deprecated on intrinsic elements (tw.button, tw.div, …): prefer tw.element(base, config) — same types and runtime as tw.element.cva(base, config). The .cva() member remains available but may be removed in a future major version.
Creates a styled component with variant support using class-variance-authority.
Signature
Preferred for intrinsics (see above):
tw.element(baseClasses, config);Equivalent legacy form:
tw.element.cva(baseClasses, config);Parameters
baseClasses(string): Base CSS classes that are always appliedconfig(object): CVA configuration objectvariants(object): Variant definitionsdefaultVariants(object, optional): Default variant valuescompoundVariants(array, optional): Compound variant definitions
Example
const Button = tw.button("btn-base", {
variants: {
$variant: {
primary: "btn-primary",
secondary: "btn-secondary",
},
$size: {
sm: "btn-sm",
md: "btn-md",
lg: "btn-lg",
},
},
defaultVariants: {
$variant: "primary",
$size: "md",
},
compoundVariants: [
{
$variant: "primary",
$size: "lg",
className: "btn-primary-lg",
},
],
});
// Using default variants - they're applied automatically
<Button>Click me</Button>; // Uses primary variant and md size
// Override defaults
<Button $variant="secondary" $size="sm">
Small Secondary
</Button>;Boolean shorthand
A string as a variant is a boolean variant. The prop type is boolean.
const Frame = tw.div("rounded p-4", {
variants: {
$active: "ring-2 ring-blue-500", // same as { true: "ring-2 ring-blue-500", false: "" }
$tone: { info: "bg-blue-50", tip: "bg-green-50" },
},
compoundVariants: [{ $active: true, $tone: "info", className: "font-bold" }],
});
<Frame $active={isActive} />;Use the object form ({ true: "…", false: "…" }) when the false value also needs classes.
compoundVariants and defaultVariants use true and false for the shorthand too.
Transient Props
Variant keys starting with $ are transient props that won't be passed to the
DOM element. This prevents React warnings about unknown props.
Intrinsic shorthand (tw.element(base, config))
For intrinsic factories (tw.button, tw.a, tw.div, …), omit .cva and pass the same arguments (preferred; .cva() on intrinsics is deprecated — see above):
tw.element(baseClasses, cvaConfig);
// equivalent to:
tw.element.cva(baseClasses, cvaConfig);Tagged templates (tw.div`classes` ) are unchanged. Dispatch treats the first argument as CVA config when it is not a tagged-template receiver. See isTaggedTemplateArg under Utilities.
.withProps()
Sets default props for a component. User-provided props will override these defaults.
Signature
Component.withProps(defaultProps);Parameters
defaultProps(object): An object containing default props to apply
Example
const Button = tw.button("btn", {
variants: {
$variant: {
primary: "btn-primary",
secondary: "btn-secondary",
},
},
})
.withProps({
type: "button",
"data-testid": "button",
$variant: "primary",
});Template components have .withProps() too. The result keeps .withStyle() and .withProps(), so you can chain them:
// pin a wrapped component's own props
const BannerLink = tw(Button)`h-auto p-0 underline`.withProps({
variant: "link",
});
const SubmitButton = tw.button`px-4 py-2`
.withProps({ type: "submit" })
.withStyle({ minWidth: 120 });In Vue, withProps uses Vue's mergeProps, so a default class and a call-site class are joined.
In React and Solid, a call-site prop replaces the default.
$as Prop
The $as prop allows you to render a component as a different element or component.
Example
const Button = tw.button`btn`;
// Render as an anchor tag
<Button $as="a" href="/link">
Link Button
</Button>;
// Render as a custom component
<Button $as={Link} href="/link">
Next.js Link
</Button>;
// Works with CVA components too
const VariantButton = tw.button("btn", {
variants: {
$variant: {
primary: "btn-primary",
secondary: "btn-secondary",
},
},
});
<VariantButton $as="a" href="/link" $variant="primary">
Link Button
</VariantButton>;PolymorphicComponentProps
Utility type for rendering CVA components as custom React components (TanStack Router Link, Next.js Link, etc.) while preserving every $-prefixed variant prop ($variant, $size, $tone, …) from the source component.
Use it when the runtime $as={SomeComponent} form needs explicit typing (e.g. when wrapping in your own component):
import { Link, type LinkProps } from "@tanstack/react-router";
import tw, { type PolymorphicComponentProps } from "@styled-cva/react";
const Button = tw.button("btn", {
variants: {
$variant: { primary: "btn-primary", secondary: "btn-secondary" },
$size: { sm: "px-2", md: "px-3" },
},
});
type ButtonLinkProps = PolymorphicComponentProps<typeof Button, typeof Link> &
LinkProps;
const ButtonLink = (props: ButtonLinkProps) => (
<Button {...props} $as={Link} />
);
// Now type-safe end-to-end:
<ButtonLink to="/about" $variant="primary" $size="md">
About
</ButtonLink>;For intrinsic elements ($as="a", $as="button", …) the typing already works without this utility — it's only needed when $as is a custom component.
Utilities
cn
A utility function for combining Tailwind CSS classnames. It uses cn for intelligent merging and conflict resolution optimized for Tailwind CSS v4.
import { cn } from "@styled-cva/react";
const className = cn("text-red-500", "bg-blue-500");
// className = "text-red-500 bg-blue-500"isTaggedTemplateArg
From @styled-cva/core, re-exported by framework packages: true when the value is a tagged-template TemplateStringsArray (has raw). Used internally to distinguish tw.div`...` from tw.div(base, config).
import { isTaggedTemplateArg } from "@styled-cva/react";cva
The underlying class-variance-authority function. You can use it directly if needed:
import { cva } from "@styled-cva/react";
const buttonVariants = cva("btn-base", {
variants: {
variant: {
primary: "btn-primary",
secondary: "btn-secondary",
},
},
});
// Use with className
<button className={buttonVariants({ variant: "primary" })}>Click me</button>;When using cva directly (not through tw.element.cva()), variant keys don't
need the $ prefix since they're not passed as props to components. The $
prefix is only needed when using tw.element.cva() to prevent props from
being passed to the DOM.
TypeScript Types
TailwindComponent<P, O>
The base type for all styled components.
P: The base React propsO: Additional props added by the template function
VariantProps<T>
Extracts variant props from a CVA configuration.
import { cva, type VariantProps } from "@styled-cva/react";
const buttonVariants = cva("btn", {
variants: {
$variant: {
primary: "btn-primary",
secondary: "btn-secondary",
},
},
});
type ButtonVariants = VariantProps<typeof buttonVariants>;
// { $variant?: 'primary' | 'secondary' }VariantProps works on a cva function, not on a styled component. For a styled component, use VariantsOf and VariantOf.
VariantsOf<C> and VariantOf<C, K>
Read the variant types from a styled component. Then you do not need a separate cva only for the types.
import tw, { type VariantOf, type VariantsOf } from "@styled-cva/react";
const Callout = tw.div("rounded p-4", {
variants: {
$tone: { info: "bg-blue-50", tip: "bg-green-50" },
$active: { true: "ring-2", false: "" },
},
});
type CalloutVariants = VariantsOf<typeof Callout>;
// { $tone?: "info" | "tip" | null; $active?: boolean | null }
type Tone = VariantOf<typeof Callout, "$tone">; // "info" | "tip"
type Active = VariantOf<typeof Callout, "$active">; // boolean
const toneIcon: Record<Tone, string> = { info: "ℹ️", tip: "💡" };VariantsOfgives all$-prefixed props of the component, without$as.VariantOfgives the values of one variant, withoutnullandundefined.- A boolean variant (
{ true, false }or the string shorthand) givesboolean. - They work on
tw.tag(base, config),tw(Component, base, config),.withProps()results and template components. For a template component, they give the$props of its type parameter.
Advanced: .withStyle()
For additional flexibility, basic styled components (not CVA components) support .withStyle() to add inline styles:
const Button = tw.button`btn`.withStyle({
transition: "all 0.2s",
});This is only available on basic styled components created with template literals. CVA components do not support this method.