shadcn is a library that provides UI components built with Radix UI and Tailwind CSS .
To handle class merging efficiently, shadcn
uses three key mechanisms. Let's break them down.
cn
Utility Function
shadcn
includes a helper function called cn
that simplifies class merging:
tsx
CopyEdit
import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
This function combines two powerful utilities:
clsx
: A Flexible Class String Builder
clsx helps transform various class formats into a valid class string:
const result = clsx({ foo: true }, "other", ["bar", "christmas"]);
console.log(result); // "foo other bar christmas
This utility provides a syntax similar to Vue.js's class binding, making it familiar to many developers.
twMerge
: A Smarter Tailwind Class Merger
twMerge intelligently merges Tailwind classes, resolving conflicts:
const result = twMerge("bg-red bg-blue");
console.log(result); // "bg-blue"
Since Tailwind classes like bg-red
and bg-blue
conflict, twMerge
ensures only the last applicable class is kept.
class-variance-authority
(cva
) Utility
class-variance-authority
(or cva
) helps define component variants in a structured way.
Here’s an example of how to create a button with size variants:
// components/button.ts
import { cva } from "class-variance-authority";
const button = cva("font-semibold border rounded", {
variants: {
size: {
small: ["text-sm", "py-1", "px-2"],
medium: ["text-base", "py-2", "px-4"],
},
},
defaultVariants: {
size: "medium",
},
});
console.log(button());
// "font-semibold border rounded text-base py-2 px-4"
console.log(button({ size: "small" }));
// "font-semibold border rounded text-sm py-1 px-2"
You can also extend the component’s classes dynamically, for example, to inherit styles from a parent:
console.log(button({ size: "small", className: "mb-3" }));
// "font-semibold border rounded text-sm py-1 px-2 mb-3"
By combining clsx
, twMerge
, and cva
, shadcn
ensures robust and maintainable class merging. These utilities help developers manage styles efficiently while keeping their UI code clean and scalable.