Overview
The utilities module provides helper functions for managing CSS class names in React components, particularly when working with TailwindCSS and conditional styling.
The cn utility function combines and merges CSS class names intelligently, handling conflicts and conditional classes with ease. It leverages clsx for flexible class name composition and tailwind-merge for proper TailwindCSS class merging.
Function Signature
function cn ( ... inputs : ClassValue []) : string
Parameters
A variable number of class name inputs. Each input can be:
A string of class names
An object with class names as keys and boolean values
An array of class names
undefined or null (automatically filtered out)
Any combination of the above
Returns
A merged string of CSS class names with TailwindCSS conflicts resolved. Later classes override earlier ones when conflicts occur.
Usage Examples
Basic Usage
import { cn } from '@/lib/utils' ;
// Simple class concatenation
const className = cn ( 'text-red-500' , 'font-bold' );
// Result: "text-red-500 font-bold"
Conditional Classes
import { cn } from '@/lib/utils' ;
const isActive = true ;
const hasError = false ;
const className = cn (
'base-class' ,
isActive && 'active-class' ,
hasError && 'error-class'
);
// Result: "base-class active-class"
TailwindCSS Conflict Resolution
import { cn } from '@/lib/utils' ;
// Later classes override earlier ones
const className = cn ( 'text-red-500' , 'text-blue-500' );
// Result: "text-blue-500" (not "text-red-500 text-blue-500")
const responsiveClass = cn ( 'p-4' , 'md:p-8' , 'lg:p-12' );
// Result: "p-4 md:p-8 lg:p-12" (no conflicts, different breakpoints)
Object Syntax
import { cn } from '@/lib/utils' ;
const isPrimary = true ;
const isDisabled = false ;
const className = cn ({
'bg-blue-500' : isPrimary ,
'bg-gray-500' : ! isPrimary ,
'opacity-50' : isDisabled ,
'cursor-pointer' : ! isDisabled
});
// Result: "bg-blue-500 cursor-pointer"
React Component Example
import { cn } from '@/lib/utils' ;
interface ButtonProps {
variant ?: 'primary' | 'secondary' ;
size ?: 'sm' | 'md' | 'lg' ;
className ?: string ;
}
const Button : React . FC < ButtonProps > = ({
variant = 'primary' ,
size = 'md' ,
className
}) => {
return (
< button
className = { cn (
// Base styles
'rounded font-semibold transition-colors' ,
// Variant styles
{
'bg-blue-500 text-white hover:bg-blue-600' : variant === 'primary' ,
'bg-gray-200 text-gray-800 hover:bg-gray-300' : variant === 'secondary' ,
},
// Size styles
{
'px-3 py-1 text-sm' : size === 'sm' ,
'px-4 py-2 text-base' : size === 'md' ,
'px-6 py-3 text-lg' : size === 'lg' ,
},
// User-provided classes (can override defaults)
className
)}
>
Click me
</ button >
);
};
// Usage
< Button variant = "primary" size = "lg" className = "shadow-lg" />
Dependencies
The cn function requires the following npm packages: npm install clsx tailwind-merge
clsx : Flexible utility for constructing className strings
tailwind-merge : Intelligently merges TailwindCSS classes without conflicts
Why Use cn?
Conflict Resolution : Automatically resolves TailwindCSS class conflicts (e.g., text-red-500 and text-blue-500)
Conditional Logic : Clean syntax for applying classes based on conditions
Type Safety : Full TypeScript support with ClassValue types
Flexibility : Accepts multiple input formats (strings, objects, arrays)
Developer Experience : Reduces boilerplate and improves code readability
Performance : Optimized for runtime performance with minimal overhead
Implementation Details
import { ClassValue , clsx } from "clsx" ;
import { twMerge } from "tailwind-merge" ;
export function cn ( ... inputs : ClassValue []) {
return twMerge ( clsx ( inputs ));
}
The function works in two steps:
clsx : Combines all inputs into a single class string, filtering out falsy values
twMerge : Merges TailwindCSS classes, resolving conflicts by keeping the last occurrence