Polymorphism
cva components are polymorphic (and framework-agnostic) by default; just apply the class to your preferred HTML element…
import { button } from "./components/button";
export default () => ( <a className={button()} href="/sign-up"> Sign up </a>);Alternative Approaches
React
If you’d prefer to use a React-based API, cva strongly recommends using Base UI’s useRender hook to roll your own render prop.
"use client";import { cva, type VariantProps } from "cva";import { useRender } from "@base-ui/react/use-render";import { mergeProps } from "@base-ui/react/merge-props";
const _BUTTON_DEFAULT_TAG = "button" satisfies React.ElementType;
export interface ButtonProps extends useRender.ComponentProps<typeof _BUTTON_DEFAULT_TAG>, VariantProps<typeof button> {}
const button = cva({ base: "button", variants: { intent: { primary: "bg-blue-500 hover:bg-blue-600 border-transparent text-white", secondary: "border-gray-400 bg-white text-gray-800 hover:bg-gray-100", }, },});
export function Button({ render, intent = "primary", className, ...props}: ButtonProps) { const defaultProps: useRender.ElementProps<typeof _BUTTON_DEFAULT_TAG> = { className: button({ intent, className }), // Consider data-attributes for debugging purposes ["data-button" as string]: "", ["data-intent" as string]: intent, };
return useRender({ defaultTagName: _BUTTON_DEFAULT_TAG, render, props: mergeProps<typeof _BUTTON_DEFAULT_TAG>(defaultProps, props), });}Usage
import { Button } from "./components/button";
// Renders:// <a href="/sign-up" class="button bg-blue-500 text-white border-transparent hover:bg-blue-600">// Sign up// </a>export default () => <Button render={<a href="/contact" />}>Contact</Button>;