디자인 시스템 개발일지 3 ( 스타일 관련 유틸 함수 정리 )
스타일 관련 유틸 함수
스타일 관련 유틸함수가 필요한 이유
- tailwind-variant로 생성해서 지정한 props와, className을 통해 받는 props를 다 가능하게 할 경우 스타일들이 겹치는 문제가 발생한다.
- 디자인 시스템을 구성하는 경우 default 스타일링과 사용자가 추가로 className을 입력하여 override되는 스타일이 있다.
- 이 때, 스타일들을 적용함에 있어서 우선순위가 중요한데, 어떤 방식으로 합칠지 명시를 해주는 것이 스타일 병합 유틸의 역할이다.
<스타일 병합 유틸을 쓰지 않는 경우>
export const Component = ({className, ...props}: Props) => {
const componentStyles = getComponentStyles(props)
return (
<div className = {`${componentStyles} ${className}`}>
text
</div>)
}
- 이것도 마찬가지로 동작하긴 한다.
- props를 통해 조합된 componentStyles 기반으로
- 하지만 단순 className의 선언 순서로 우선순위가 결정되기 때문에 안정성이 부족하고, 가독성은 좋지 않다.
clsx & twMerge
clsx
- 조건부로 클래스 이름을 결합하고 관리하는데 사용되는 함수
- 여러 개의 클래스를 조건에 따라 동적으로 쉽게 결합
- 불필요한 빈 문자열이나 null, undefined 같은 값들을 자동으로 걸러준다.
- 이전에 나왔던 className을 문자열 그대로 넣는 방식에서는 undefined 처리가 자동으로 되지 않는다.
- ClassValue[] 타입을 input으로 받음.
<예제>
clsx(
'btn',
isActive && 'btn-active',
isDisabled && 'btn-disabled'
);
twMerge
- className 충돌 막아주면서, 겹치는 className의 경우 마지막에 선언된 className 기준 오버라이드 처리됨.
- tailwind 유틸리티 클래스로 등록되어있지 않은 className은 자동으로 삭제해준다.
import { twMerge } from 'tailwind-merge'
twMerge('px-2 py-1 bg-red-600 p-3 bg-grey-800')
// => p-3 bg-grey-800
cn ( 개인 프로젝트에서는 mergeStyles )
- 저 둘을 통합한 방식이다.
- clsx로 클래스네임들을 관리하고, twMerge로 겹치는 className까지 제거
import { ClassValue, clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';
export const cn = (...inputs: ClassValue[]) => {
return twMerge(clsx(inputs));
};