cssreactjstailwind-cssclsx

What is the difference between the clsx and cva NPM packages?


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?


Solution

  • 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:

    Tailwind CSS Documentation

    clsx Documentation

    cva Documentation