# @styled-cva/react (styled-cva)
> A typesafe, class-variance-authority-based, styled-components-like library for authoring React components
## Documentation
- [Introduction](https://styled-cva.vercel.app/)
- [Getting Started](https://styled-cva.vercel.app/getting-started)
- [Examples](https://styled-cva.vercel.app/examples)
- [Testing](https://styled-cva.vercel.app/testing)
- [API Reference](https://styled-cva.vercel.app/api)
- [ESLint Plugin](https://styled-cva.vercel.app/eslint-plugin)
- [MCP Docs Server](https://styled-cva.vercel.app/mcp)
## MCP Server
- Endpoint: https://styled-cva.vercel.app/api/mcp
- Description: Model Context Protocol server providing documentation as resources and tools for search.
## Features
- **Type-safe**: Full TypeScript support with variant inference.
- **CVA-based**: Built on top of class-variance-authority.
- **Styled-components-like**: Familiar API for those coming from styled-components or emotion.
- **Tailwind CSS**: Designed to work seamlessly with Tailwind CSS.
- **Polymorphic**: Support for the `$as` prop to change the rendered element.
## Usage Examples
# Usage Examples
Common patterns and real-world examples using `styled-cva`.
## Buttons
### Basic Button with Variants
A standard button component with `intent` and `size` variants.
```tsx
import tw from "@styled-cva/react";
const Button = tw.button.cva(
"inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none ring-offset-background",
{
variants: {
$variant: {
default: "bg-primary text-primary-foreground hover:bg-primary/90",
destructive:
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
outline:
"border border-input hover:bg-accent hover:text-accent-foreground",
secondary:
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "underline-offset-4 hover:underline text-primary",
},
$size: {
default: "h-10 py-2 px-4",
sm: "h-9 px-3 rounded-md",
lg: "h-11 px-8 rounded-md",
icon: "h-10 w-10",
},
},
defaultVariants: {
$variant: "default",
$size: "default",
},
},
);
export default function ButtonExample() {
return (
);
}
```
## Form Elements
### Input with Validation States
An input component that handles error, success, and disabled states.
```tsx
import tw from "@styled-cva/react";
const Input = tw.input.cva(
"flex h-10 w-full rounded-md border bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
{
variants: {
$state: {
default: "border-input focus-visible:ring-ring",
error:
"border-red-500 focus-visible:ring-red-500 text-red-900 placeholder:text-red-300",
success: "border-green-500 focus-visible:ring-green-500 text-green-900",
},
},
defaultVariants: {
$state: "default",
},
},
);
export default function InputExample() {
return (
);
}
```
## Interactive Components
### Toggle Switch
A switch component using `aria-pressed` or a custom prop for state.
```tsx
import { useState } from "react";
import tw from "@styled-cva/react";
const SwitchRoot = tw.button.cva(
"peer inline-flex h-[24px] w-[44px] shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50",
{
variants: {
$checked: {
true: "bg-primary",
false: "bg-input",
},
},
},
);
const SwitchThumb = tw.span.cva(
"pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform",
{
variants: {
$checked: {
true: "translate-x-5",
false: "translate-x-0",
},
},
},
);
export default function SwitchExample() {
const [checked, setChecked] = useState(false);
return (
setChecked(!checked)}
role="switch"
aria-checked={checked}
>
);
}
```
## Layouts
### Card
A composed card component.
```tsx
import tw from "@styled-cva/react";
const Card = tw.div`rounded-lg border bg-card text-card-foreground shadow-sm`;
const CardHeader = tw.div`flex flex-col space-y-1.5 p-6`;
const CardTitle = tw.h3`text-2xl font-semibold leading-none tracking-tight`;
const CardDescription = tw.p`text-sm text-muted-foreground`;
const CardContent = tw.div`p-6 pt-0`;
const CardFooter = tw.div`flex items-center p-6 pt-0`;
export default function CardExample() {
return (
Create project
Deploy your new project in one-click.
Project details form goes here...
);
}
```
## Polymorphic Components
Using the `$as` prop to render a button as a link.
```tsx
import Link from "next/link";
import tw from "@styled-cva/react";
const Button = tw.button.cva(
"inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2",
);
export default function PolymorphicExample() {
return (
);
}
```
## Advanced Composition
### Extending Components
Styling a custom component or extending an existing one.
```tsx
import tw from "@styled-cva/react";
// Base component
const BaseBox = tw.div`p-4 border rounded`;
// Extended component overrides styles
const WarningBox = tw(BaseBox)`border-yellow-500 bg-yellow-50 text-yellow-900`;
// Custom React Component
const UserProfile = ({
className,
name,
}: {
className?: string;
name: string;
}) => (
{name}
);
// Styled Custom Component
const StyledProfile = tw(
UserProfile,
)`flex items-center gap-2 p-2 bg-gray-100 rounded-full`;
export default function AdvancedCompositionExample() {
return (
Base Box
Warning Box
);
}
```
## Default Props
### Pre-configuring Components
Using `.withProps()` to set default attributes and variant values.
```tsx
import tw from "@styled-cva/react";
const IconButton = tw.button
.cva(
"inline-flex items-center justify-center rounded-full p-2 transition-colors",
{
variants: {
$variant: {
primary: "bg-blue-600 text-white hover:bg-blue-700",
ghost: "hover:bg-gray-100 text-gray-600",
},
},
},
)
.withProps({
type: "button",
$variant: "primary",
"aria-label": "Icon button",
});
export default function DefaultPropsExample() {
return (
{/* Uses all defaults */}
🚀
{/* Overrides default variant */}
⚙️
{/* Overrides default aria-label */}
🛠️
);
}
```