tailwind-merge 설정하기
tailwind-merge는 Tailwind CSS 사용 시 발생할 수 있는 클래스 충돌 문제를
마지막에 위치한 클래스만을 남겨두는 방식으로 병합하여 해결하는 라이브러리다.
className="sticky absolute relative" // relative
className="px-3 py-4 p-2" // p-2
tailwind-merge는 Tailwind CSS의 설정을 건드리지 않았을 경우 정상적으로 동작한다.
그러나, 커스텀 설정을 사용할 경우 tailwind-merge에 이를 설정해주지 않는다면 정상적으로 동작하지 않을 수 있다.
(정확하게는 기본 Tailwind CSS 설정에 없는 className을 지정할 경우)
className="text-customBlueColor text-small" // text-small
className="px-large py-small p-medium" // px-large py-small p-medium
위처럼 text에 색상과 크기를 커스텀 설정으로 지정해줄 경우
tailwind-merge에서는 이를 인지하지 못해 text-라는 prefix를 가진 클래스를 전부 병합해 글씨 크기만 남게 된다.
혹은 커스텀 spacing을 사용하는 경우, padding이나 margin에 대해서 정상적인 병합이 이루어지지 않게 된다.
이를 해결하기 위해서는 tailwind-merge 설정에 커스텀한 Tailwind CSS의 설정을 인지시켜줄 필요가 있다.
오늘은 이 tailwind-merge 설정을 어떻게 하면 되는지 알아보자.
tailwind-merge에 커스텀 설정을 적용하는 방법
tailwind-merge에서 커스텀 설정을 적용하는 가장 쉬운 방법은 extendTailwindMerge 함수를 사용하는 것이다.
extendTailwindMerge는 기존의 tailwind-merge 설정에 커스텀 설정을 추가해주는 함수이다.
//customTwMerge.ts
import { extendTailwindMerge } from "tailwind-merge";
const twMerge = extendTailwindMerge({
//커스텀 설정
...
});
export default twMerge;
위처럼 extendTailwindMerge 함수로 내부 설정을 적어주고, 이를 export 해준다.
사용할 때는 export된 twMerge 함수를 사용하면 된다.
import { cx } from "class-variance-authority";
import { ClassNameValue } from "tailwind-merge";
import twMerge from "./customTwMerge";
const classMerge = (classes: ClassNameValue[]) => {
return twMerge(cx(classes));
};
export default classMerge;
tailwind-merge 설정 구조
사용방법을 알았으니 이제 설정 방법을 알아보자.
tailwind-merge 설정 구조는 아래와 같다.
const tailwindMergeConfig = {
// ↓ Set how many values should be stored in cache.
cacheSize: 500,
// ↓ Optional prefix from TaiLwind config
prefix: 'tw-',
// ↓ Optional separator from TaiLwind config
separator: '_',
theme: {
// Theme scales are defined here
// This is not the theme object from your Tailwind config
},
classGroups: {
// Class groups are defined here
},
conflictingClassGroups: {
// Conflicts between class groups are defined here
},
conflictingClassGroupModifiers: {
// Conflicts between postfix modifier of a class group and another class group are defined here
},
}
여기서 커스텀 설정에 대해서 수정해야할 부분은
theme, classGroups, conflictingClassGroups, conflictingClassGroupModifiers이다.
하나씩 알아보자.
- theme
theme은 커스텀 설정의 color, spacing, borderRadius와 같은 설정들을 tailwind-merge에 알려주는 설정이다.
tailwind-merge의 default-config.ts에서는 theme을 아래와 같이 설정해놓고 있다.
//default-config.ts
theme: {
colors: [isAny],
spacing: [isLength],
blur: ['none', '', isTshirtSize, isArbitraryValue],
brightness: getNumber(),
borderColor: [colors],
borderRadius: ['none', '', 'full', isTshirtSize, isArbitraryValue],
borderSpacing: getSpacingWithArbitrary(),
borderWidth: getLengthWithEmpty(),
contrast: getNumber(),
grayscale: getZeroAndEmpty(),
hueRotate: getNumberAndArbitrary(),
invert: getZeroAndEmpty(),
gap: getSpacingWithArbitrary(),
gradientColorStops: [colors],
gradientColorStopPositions: [isPercent, isArbitraryLength],
inset: getSpacingWithAutoAndArbitrary(),
margin: getSpacingWithAutoAndArbitrary(),
opacity: getNumber(),
padding: getSpacingWithArbitrary(),
saturate: getNumber(),
scale: getNumber(),
sepia: getZeroAndEmpty(),
skew: getNumberAndArbitrary(),
space: getSpacingWithArbitrary(),
translate: getSpacingWithArbitrary(),
},
- classGroups
classGroups는 위의 theme에서 설정한 부분 외의 부분들을 설정해주는 공간이다.
//default-config.ts
position: ['static', 'fixed', 'absolute', 'relative', 'sticky'],
default-config에는 위와 같이 설정되어있는데 배열 내에 속한 속성들을 중복되는 속성으로 취급하겠다는 설정이다.
이 설정을 통해 아래와 같은 병합이 이루어진다.
className="sticky absolute relative" // relative
이 외에 어떤 것들이 있는지는 tailwind-merge의 default-config.ts의 classGroups를 참조하자.
- conflictingClassGroups
conflictingClassGroups은 충돌 시 제거될 클래스들을 설정하는 부분이다.
//default-config.ts
p: ['px', 'py', 'ps', 'pe', 'pt', 'pr', 'pb', 'pl'],
default-config에는 위와 같이 설정되어있는데 배열 내의 태그들이 p라는 태그와 중복되는 태그라고 설정하는 것이다.
이 설정을 통해 만약 px가 p보다 앞에 있으면 px가 제거된다.
(px가 p보다 뒤에 있으면 제거되지 않는다.)
className="px-3 py-4 p-2" // p-2
이 역시 이외에 어떤 것들이 있는지는 tailwind-merge의 default-config.ts의 conflictingClassGroups를 참조하자.
- conflictingClassGroupModifiers
conflictingClassGroupModifiers는 conflictingClassGroups에 postfix가 사용되는 경우,
이 postfix와 겹치는 클래스들을 제거하기 위한 설정이다.
className="text-small/7"
예를 들어 위와 같이 Tailwind CSS에서는 글씨 크기 small 뒤에 /7이라는 postfix가 설정될 수 있는데
이는 line-height를 설정하는 것이다.
만약 이 클래스 앞에 line-height에 관한 클래스가 존재한다면 이를 병합 시 제거해야하는데,
conflictingClassGroupModifiers는 이 경우 제거할 클래스들을 설정하는 곳이라 이해하면 된다.
//default-config.ts
'font-size': ['leading'],
default-config에는 위와 같이 설정되어있는데 이 설정을 통해 아래와 같은 병합이 이루어진다.
(leading은 Tailwind CSS에서 line-height를 설정하는 클래스 이름)
className="leading-3 text-small/7" // text-small/7
설정하기
import resolveConfig from "tailwindcss/resolveConfig";
import { extendTailwindMerge } from "tailwind-merge";
import tailwindConfig from "@root/tailwind.config";
const customTailwindTheme = resolveConfig(tailwindConfig).theme;
const getToken = (tokenName: Exclude<keyof typeof customTailwindTheme, "extend">) =>
Object.keys(customTailwindTheme[tokenName]).filter((key) => key !== "DEFAULT");
const twMerge = extendTailwindMerge({
theme: {
colors: getToken("colors"),
spacing: getToken("spacing"),
borderRadius: getToken("borderRadius"),
borderWidth: getToken("borderWidth"),
},
classGroups: {
"font-size": [{ text: getToken("fontSize") }],
},
});
export default twMerge;
``;
커스텀한 Tailwind config로부터 token을 가져오는 getToken 함수를 설정하여 twMerge를 설정해주었다.
뭔가 tailwind-merge에 fromTheme이라는 함수가 있어서 써보려고 했는데 이런 목적으로 쓰는 함수가 아닌지
계속 에러가 나는 바람에 이런 방식으로 대체했다.
만약 getToken 함수 없이 설정하고 싶다면 아래처럼 직접 적어주면 된다.
import { extendTailwindMerge } from "tailwind-merge";
const twMerge = extendTailwindMerge({
theme: {
colors: [
"current",
"transparent",
"primary",
"primary-on",
"primary-fixed",
"primary-fixed-on",
"secondary",
"secondary-on",
"secondary-fixed",
"secondary-fixed-on",
"tertiary",
"tertiary-on",
"tertiary-fixed",
"tertiary-fixed-on",
"surface",
"surface-variant",
"surface-variant-high",
"surface-variant-highest",
"surface-on",
"surface-on-variant",
"outline",
"outline-variant",
"red",
"red-on",
"red-variant",
"red-variant-on",
"yellow",
"yellow-on",
"green",
"green-on",
"magenta",
"magenta-on",
],
spacing: ["3xs", "2xs", "xs", "s", "m", "l", "xl", "2xl", "3xl"],
borderRadius: ["none", "xs", "s", "m", "l", "circle"],
borderWidth: ["s", "m"],
},
classGroups: {
"font-size": [{ text: ["inherit", "xs", "s", "m", "l", "xl", "2xl"] }],
},
});
export default twMerge;
위와 같이 tailwind 설정을 import하여 사용하는 방법은 프로젝트 설정에 따라 다르지만,
나의 경우 tailwind.config 파일이 es6 module(import/export) 방식이어야 사용 할 수 있었다.
혹시 tailwind.config를 import/export로 해야하는데 commonJS로 설정되어있다면,
아래 명령어를 통해 tailwind.config를 다시 만들고 재설정해주면 된다.
기존 설정 파일이 날라갈 수 있으니 필히 백업해두자.
//TypeScript
npx tailwindcss init --ts
//JavaScript import/export
npx tailwindcss init --esm
이제 커스텀한 tailwond 테마를 사용해도 정상적으로 merge될 것이다.
관련 글
Tailwind에서 재사용 가능한 컴포넌트로
Tailwind에서 재사용 가능한 컴포넌트로 지금까지 아토믹 디자인을 적용해 UI의 시각적인 요소들을 토큰이라는 계층으로 분류하고, 이 토큰들을 Tailwind에서 사용할 수 있도록 class로 옮겼다. 드디
bh2980.tistory.com
Reference
GitHub - dcastil/tailwind-merge: Merge Tailwind CSS classes without style conflicts
Merge Tailwind CSS classes without style conflicts - GitHub - dcastil/tailwind-merge: Merge Tailwind CSS classes without style conflicts
github.com
Tailwind CSS v3.3: Extended color palette, ESM/TS support, logical properties, and more - Tailwind CSS
Tailwind CSS v3.3 is here — bringing a bunch of new features people have been asking for forever, and a bunch of new stuff you didn't even know you wanted.
tailwindcss.com
'Frontend > CSS' 카테고리의 다른 글
디자인 시스템에서 Tailwind로 (0) | 2023.07.31 |
---|