I'm a React dev and am learning more about making flexible component libraries. I have been trying out tools to make my Tailwind more flexible and I came across these packages. I recently tried using Shadcn and see that they use both clsx
and cva
. Can someone explain the difference between them? What are good use cases for each?
Tailwind CSS is a framework that lets you style your elements by adding class names that represent different properties, such as colors, sizes, margins, etc.
For example:
<div class="bg-blue-500 text-white p-4">Hello</div>
This div
element has a blue background, white text, and some padding around it.
However, sometimes you may want to change the style of your elements based on some conditions, such as props, state, or logic. For example, you may want to change the background color of a button based on whether it is clicked or not.
This is where clsx
and cva
come in handy. They are tools that help you apply class names conditionally and create variants for your components.
clsx
is a tool that lets you combine different class names into one string based on some conditions.
For example:
import clsx from "classnames";
const btnType = "primary";
// using strings
clsx("btn", "btn--large"); // => "btn btn--large"
// using objects
clsx("btn", { [`btn--${btnType}`]: true }); // => "btn btn--primary"
// using arrays
clsx(["btn", { [`btn--${btnType}`]: true }]); // => "btn btn--primary"
// using functions
clsx("btn", () => ({ [`btn--${btnType}`]: true })); // => "btn btn--primary"
You can use clsx
to apply different class names to your elements based on props, state, or logic.
For example:
const Button = ({ type, children }) => {
const className = clsx("btn", {
"btn--primary": type === "primary",
"btn--secondary": type === "secondary",
});
return <button className={className}>{children}</button>;
};
cva
is a tool that lets you create and manage variants for your components. Variants are different styles and behaviors that you can apply to your components based on some options.
For example:
import { cva } from "class-variance-authority";
const button = cva("btn", {
variants: {
intent: {
primary: "btn--primary",
secondary: "btn--secondary",
},
size: {
small: "btn--small",
medium: "btn--medium",
},
},
compoundVariants: [
{
intent: "primary",
size: "medium",
class: "btn--primary-small",
},
],
defaultVariants: {
intent: "secondary",
size: "small",
},
});
You can use cva
to create reusable and customizable components with different variants.
For example:
const Button = ({ intent, size, children }) => {
const button = cva("btn", {
variants: {
intent: {
primary: "btn--primary",
secondary: "btn--secondary",
},
size: {
small: "btn--small",
medium: "btn--medium",
},
},
compoundVariants: [
{
intent: "primary",
size: "medium",
class: "btn--primary-small",
},
],
defaultVariants: {
intent,
size,
},
});
return <button className={button.className}>{children}</button>;
};
To learn more, please see: