# @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 (
{/* Renders as {/* Renders as */} {/* Renders as Next.js Link */}
); } ``` ## 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 */} 🛠️
); } ```