This library makes building design systems so much fun

Just a guy who loves to write code and watch anime.
Search for a command to run...

Just a guy who loves to write code and watch anime.
No comments yet. Be the first to comment.
Qualities that make outstanding builders.

Bipedal vs quadrupedal: how many legs This is about the number of legs the creature walks on. Bipedal. Two legs. Humans, ostriches, T-rex, kangaroos, most fantasy humanoids. Quadrupedal. Four legs. Do

Intro You hear "lerp" and "smoothstep" everywhere in game dev. They sound like math jargon. They're not. Both are small tools that do the same job: smoothly move from one value to another. The problem

What is Kinematics Kinematics is the math field. It's the study of how things move without worrying about forces (which would be dynamics). FK and IK are the two branches: forward kinematics and inver

Intro Textures are usually the biggest cost in a 3D scene. Memory, bandwidth, and load time all get eaten by them. Resizing them is the obvious lever. There's more. This post is about the less obvious

I'm officially a Tailwind CSS convert. I've been using it for two months at work, and I'm loving it. ๐
I think it takes time to get around to it, but if your design system in Figma is using Tailwind, it'll make your life so much easier.
I wanna dive into the library cva which I've enjoyed so much. It makes building design systems mega fun.
I wanna share how things would look like without it and how they do with it.
This will show you a glimpse of how much easier it is to build design systems with cva.
We're also gonna be using the cn utility function.
cvaWe want to have a button component with different variants and sizes:
import React, { ComponentProps } from "react";
import { cn } from "@/lib/utils";
type ButtonProps = ComponentProps<"button"> & {
variant?: "primary" | "secondary" | "danger";
size?: "small" | "medium" | "large";
};
const Button = ({
className,
variant = "primary",
size = "medium",
...props
}: ButtonProps) => {
const buttonClasses = cn(
"rounded font-semibold focus:outline-none",
{
"bg-blue-500 hover:bg-blue-600 text-white": variant === "primary",
"bg-gray-200 hover:bg-gray-300 text-gray-800": variant === "secondary",
"bg-red-500 hover:bg-red-600 text-white": variant === "danger",
"px-4 py-2 text-sm": size === "small",
"px-6 py-3 text-base": size === "medium",
"px-8 py-4 text-lg": size === "large",
},
className
);
return <button className={buttonClasses} {...props} />;
};
export default Button;
I'm excluding forwardRef here. But if you need that, you'd have to add it. Although, it's gonna go away with React 19. ๐
The pain of building a component this way is all the conditional classes. The code becomes bloated and hard to read.
It would be nice to have a tiny thing responsible for abstracting this complexity.
cva to the rescueimport React from "react";
import { cva, VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";
const buttonVariants = cva("rounded font-semibold focus:outline-none", {
variants: {
variant: {
primary: "bg-blue-500 hover:bg-blue-600 text-white",
secondary: "bg-gray-200 hover:bg-gray-300 text-gray-800",
danger: "bg-red-500 hover:bg-red-600 text-white",
},
size: {
small: "px-4 py-2 text-sm",
medium: "px-6 py-3 text-base",
large: "px-8 py-4 text-lg",
},
},
defaultVariants: {
variant: "primary",
size: "medium",
},
});
type ButtonProps = VariantProps<typeof buttonVariants> &
React.ComponentProps<"button">;
const Button = ({
className,
variant,
size,
...props
}: ButtonProps) => {
return (
<button
className={cn(buttonVariants({ variant, size }), className)}
{...props}
/>
);
};
export default Button;
cva let's you define your variants and sizes in a single place. It abstracts the complexity of conditional classes.
The nice part here is that you don't need to worry about the typings. VariantProps<typeof buttonVariants> will take care of that for you. You can focus on the complexity of the designs in a different place. This place being the cva function.
It returns a function that you can call with the props you want to apply. It then returns the Tailwind classes you need.
If you need styles to apply when multiple variants are met, you can do that with Compound Variants.
variantsI'll be honest, variants is a bit confusing because you typically have a variant prop. But in the case of cva, variants are the props. Which would honestly be a better name for it.