1. 문제점 파악
1. 현재 tw-merge문제점
: 속성 두 개를 적을 때, 하나의 속성이 뒤의 속성을 완전히 덮어쓰지 못한다.
예를 들어, 기본적으로 Text컴포넌트의 폰트는 text-sm이라고 하자. 이 때, text-title1이라는 속성으로 이 속성을 오버라이드하려고 한다. 그렇다면 아래와 같이 작성할 것이다.
<div className="text-sm text-title1">안녕하세요</div>
-
결과
위와 같이, title1 속성이 뒤에 왔음에도, sm의 속성이 먼저 적용된다. 이에 따라 title1은 sm을 뒤집어 쓰지 못한다.
그렇다면, twMerge를 사용한다면?
💡 twMerge?
twMerge
: Tailwind 속성을 충돌 없이 합쳐준다.
예시
<div className={twMerge("p-1" ,"p-2")}>안녕하세요</div>![]()
위와 같이 뒤의 p-2이 p-1을 뒤집어 쓴다.
하지만, twMerge는 커스텀 속성을 뒤집어 쓰지 못한다.
<div className={twMerge("text-sm" ,"text-title1")}>안녕하세요</div>
그렇다면, clsx나 classNames를 사용한다면?
💡 classNames? clsx?
classNames
: className을 조건부로 합칠 때 보다 선언적으로, 간편하게 작성할 수 있게 해주는 JS유틸이다.
classNames({ 문자열 : 조건 })classNames({ 'doo', 'foo':true, 'bar':false }) // 'doo foo'clsx
: classNames와 동일한 기능을 제공한다.
clsx({ 문자열 : 조건 })clsx('foo', true && 'bar', 'baz');
clsx나 classNames는 단순히
2. 원인 파악
가설 1. 커스텀 속성이라, twMerge에 등록이 안되어 있는 게아닐까?
위에서
// tailwind.config.js
const config = require('@guesung/tailwind-config/tailwind.config');
module.exports = {
fontSize : {
title1: [
'4rem',
{
fontWeight: 'bold',
},
],
// ..
}
// ..
};
twMerge레포 > 이슈에 들어가, ‘custom’이라고 검색해보았다. 그 중 한 이슈를 들여다보았더니
https://github.com/dcastil/tailwind-merge/issues/420#issuecomment-2138146705
위와 같이 extendTailwindMerge를 이용하여, twMerge를 확장해서 사용하면 된다고 한다.
3. 문제 해결
// src/utils/cn.ts
import { fontSizes } from '@/style/theme';
import { clsx } from 'clsx';
import { extendTailwindMerge } from 'tailwind-merge';
import type { ClassValue } from 'clsx';
const customTwMerge = extendTailwindMerge({
classGroups: {
'font-size': [
{
text: Object.keys(fontSizes),
},
],
},
});
const cn = (...inputs: ClassValue[]) => {
return customTwMerge(clsx(inputs));
};
export default cn;
우리는 clsx유틸을 사용하고 있었기에, clsx를 이용해 먼저 주어진 className을 계산하고, 이를 커스텀한 twMerge에 넣어준다.
코드
<>
<div className={cn('text-sm', 'text-h1')}>TEST</div>
<div className="text-h1">h1</div>
</>
커스텀한 cn유틸함수를 적용하면 아래 사진처럼 뒤에 오는 text-h1만 남아있는 것을 확인할 수 있습니다.
👍