노트

cn 유틸리티(clsx·tailwind-merge·cva)

cn Utility (clsx, tailwind-merge, cva)

프런트엔드#css#tooling · 연결된 개념 5개

쉽게 말하면

cn은 조건에 맞는 클래스만 골라 한 줄로 합치고, px-2와 px-4처럼 같은 자리를 두고 부딪히는 Tailwind 클래스는 마지막 것만 남기는 함수예요. 같은 자리에 덧입은 옷은 맨 위 것만 보이는 것과 같죠.

비유가 깨지는 곳 옷과 달리 아래 클래스가 가려지는 게 아니라 문자열에서 아예 지워져요. 이 정리는 tailwind-merge가 하고, 조건부 합치기는 clsx, variant별 클래스 정의는 cva가 맡아요.

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'
cvavariant·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, 이 함수들을 쓰는 헤드리스 컴포넌트 구조는 컴파운드 컴포넌트 패턴.

연결된 개념

이 노트를 가리키는 문서

뜻이 가까운 노트

  • CSS 명시도

    캐스케이드에서 레이어까지 비겼을 때, 선택자가 요소를 얼마나 구체적으로 가리키는지로 승부를 내는 점수. (A, B, C) 세 자리로 매기고 앞자리부터 비교한다.

  • CSS @layer

    CSS 규칙을 이름 붙인 묶음(레이어)으로 나누고, 묶음 사이의 우선순위를 명시적으로 정하는 기능. CSS Cascade Level 5 명세에서 캐스케이드에 새 단계로 들어왔고, 명시도보다 먼저 평가된다.

  • type과 interface

    type(타입 별칭, Type Alias)과 interface는 둘 다 타입에 이름을 붙이는 방법이다. 객체 모양을 정의할 때는 대부분 바꿔 써도 되지만, 확장 방식과 표현 범위가 다르다.

  • 속성 선택자와 형제 선택자

    대괄호 []로 HTML 속성을 기준으로 요소를 고르는 선택자와, +·~로 형제 관계를 따라 고르는 선택자. CSS뿐 아니라 querySelectorAll에서도 똑같이 쓴다.

  • CSS-in-JS와 빌드 타임 CSS

    JS(JavaScript) 안에서 스타일을 정의하고, 렌더링할 때 라이브러리가 클래스를 만들어 style 태그로 주입하는 방식. styled-components와 Emotion이 대표다. React 18 이후 서버 컴포넌트(React Server Components)·스트리밍 SSR(Streaming Server-Side Rendering)이 자리 잡으면서 런타임에 CSS를 만드는 방식은 줄고, 빌드할 때 CSS를 뽑는 방식이 늘었다(2026 기준).

보기 옵션