cn()은 shadcn/ui 등에서 쓰는 클래스 이름 조합 함수로, clsx와 tailwind-merge를 합친 한 줄짜리 유틸리티다. 여기에 cva로 컴포넌트 변형(Variant)을 정의하면 Tailwind 기반 컴포넌트 API(Application Programming Interface)가 완성된다.
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}| 도구 | 하는 일 | 예 |
|---|---|---|
| clsx | 조건부 클래스를 문자열로 합침 | clsx('a', false && 'b', { c: true }) → 'a c' |
| tailwind-merge | 충돌하는 Tailwind 클래스 중 마지막만 남김 | 'px-2 py-1 px-4' → 'py-1 px-4' |
| cva | variant·size별 클래스를 타입 안전하게 정의 | 아래 예 |
const button = cva('inline-flex items-center rounded-md', {
variants: {
variant: { default: 'bg-primary text-white', outline: 'border' },
size: { sm: 'h-9 px-3', lg: 'h-11 px-8' },
},
defaultVariants: { variant: 'default', size: 'sm' },
})
<button className={cn(button({ variant, size }), className)} />- 흐름: cva가 variant에 맞는 클래스를 만들고, 사용자가 넘긴
className과 합친 뒤, tailwind-merge가 충돌을 정리한다. 그래서 바깥에서px-8을 넘기면 기본 패딩을 깔끔하게 덮어쓴다 variant값이 유니언 타입으로 추론돼 잘못된 값을 넣으면 컴파일 에러가 난다(유니언·인터섹션·리터럴 타입)
tailwind-merge 자체는 tailwind-merge와 cn(), Tailwind는 Tailwind CSS, 이 함수들을 쓰는 헤드리스 컴포넌트 구조는 컴파운드 컴포넌트 패턴.