같은 CSS 속성을 건드리는 Tailwind 클래스가 여러 개 붙었을 때, 뒤에 온 것만 남기고 앞의 것을 지워 주는 라이브러리. 컴포넌트의 기본 클래스를 사용처에서 덮어쓰는 패턴을 안전하게 만든다.
왜 필요한가
function Button({ className }) {
return <button className={`px-4 bg-blue-500 ${className}`} />
}
<Button className="px-2 bg-red-500" />
// class="px-4 bg-blue-500 px-2 bg-red-500"의도는 빨간 배경이지만 보장되지 않는다. 클래스 문자열 안의 순서는 캐스케이드와 상관이 없고, 모든 유틸리티는 명시도가 같으니 스타일시트에서 나중에 선언된 규칙이 이긴다. 그 순서는 Tailwind가 정하므로 px-4가 뒤에 있으면 px-2는 무시된다. 어떤 때는 되는 것처럼 보이다가 클래스 구성이 바뀌면 깨진다.
twMerge('px-4 bg-blue-500 px-2 bg-red-500') // 'px-2 bg-red-500'
twMerge('p-4 px-2') // 'p-4 px-2' (px만 덮음)
twMerge('rounded-md rounded-lg') // 'rounded-lg'twMerge는 어떤 클래스들이 같은 속성 그룹(padding, background, radius, display…)인지 알고 있어서 충돌만 정확히 지운다. DOM(Document Object Model)에도 쓸데없는 클래스가 남지 않는다.
clsx와의 역할 분담
clsx·classnames는 조건부로 클래스를 이어 붙이기만 하고 충돌은 해결하지 않는다. 그래서 둘을 합친 cn() 함수를 만들어 쓴다 → cn 유틸리티(clsx·tailwind-merge·cva)
export const cn = (...inputs) => twMerge(clsx(inputs))동적으로 클래스를 합칠 일이 없는 프로젝트라면 굳이 필요 없다. 반대로 컴포넌트 라이브러리처럼 기본 스타일 + className 덮어쓰기가 많다면 거의 필수다. 원리는 Tailwind CSS의 빌드 방식에서 나온다.
출처: tailwind-merge