ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Tailwind CSS 잘 활용하기 with Clxs, CVA, twMerge
    Style/Libraries 2024. 3. 31. 14:45

    최근 팀 내에서 Tailwind CSS Class를 사용할 때 좀 더 효율성 있게 작성하는 방식에 대해 논의하게 되었습니다. 기존 작업 중인 프로젝트에서는 Styled Component와 Tailwind CSS를 같이 쓰는 방식을 채택하여 사용 중인데 새롭게 들어가는 프로젝트에선 clsx, class-variance-authority, tailwind-merge를 조합하여 사용하는 방식을 사용해 보려고 합니다.

     

    필요 라이브러리

    ※ React에서 Tailwind CSS 설정이 되어 있는 환경을 가정합니다.

    clsx는 조건부 className 처리를 위해 사용되며 라이브러리 크기가 매우 작은 장점을 가지고 있습니다.

    import { clsx } from 'clsx';
    
    clsx('w-full', true && 'h-full', { 'px-4': true, 'py-2': false }, [
      'flex',
      'items-center',
    ]);
    // => w-full h-full px-4 flex items-center

     

    cva(class-variance-authority)는 props에 따른 className 처리를 위해 사용됩니다.

    import { cva } from 'class-variance-authority';
    
    export const ComponentVariants = cva(
      `
      flex items-center justify-center 
      `,
      {
        variants: {
          variant: {
            default: '',
            full: 'w-full h-full',
          },
        },
        defaultVariants: {
          variant: 'default',
        },
      },
    );
    
    // <div className={ComponentVariants({ variant })} />

     

    tailwind-mergeclassName 충돌을 막아주어 겹치는 className의 경우 마지막에 선언된 className 기준 오버라이드 처리됩니다.

    import { twMerge } from 'tailwind-merge'
    
    twMerge('px-2 py-1 bg-red-600 p-3 bg-grey-800')
    // => p-3 bg-grey-800

     

    npm install clsx class-variance-authority tailwind-merge --dev
    # or
    yarn add clsx class-variance-authority tailwind-merge --dev

     

    util 함수 작성

    clsx, class-variance-authority, tailwind-merge를 조합하여 사용하기 위해 유틸함수를 만듭니다.

    // utils/style.ts
    import { ClassValue, clsx } from 'clsx';
    import { twMerge } from 'tailwind-merge';
    
    export const cn = (...inputs: ClassValue[]) => {
      return twMerge(clsx(inputs));
    };

    clsx와 tailwind-merge를 통해 조건부 className과 className 충돌을 방지하는 유틸함수 입니다.

     

    cva와 작성된 유틸함수 cn을 활용한 Button 예제입니다.

    // components/Button.tsx
    import { cva, VariantProps } from 'class-variance-authority';
    
    import { cn } from '@/utils/style';
    
    export const ButtonVariants = cva(
      `
      flex items-center justify-center 
      bg-gray-950 text-white
      rounded-sm text-base font-medium
      `,
      {
        variants: {
          variant: {
            default: 'shadow-none',
            grey: 'bg-gray-150 text-gray-950',
            red: 'bg-red-600',
          },
          size: {
            default: 'px-2 py-1',
            md: 'px-4 py-2',
            lg: 'px-6 py-3 text-lg',
            xl: 'px-8 py-4 text-xl',
          },
        },
        defaultVariants: {
          variant: 'default',
          size: 'default',
        },
      },
    );
    
    interface ButtonProps extends VariantProps<typeof ButtonVariants> {
      className?: string;
      children?: React.ReactNode;
    }
    
    function Button({ variant, size, className, children }: ButtonProps) {
      return (
        <button className={cn(ButtonVariants({ variant, size, className }))}>
          {children && children}
        </button>
      );
    }
    
    export default Button;

     

    cva에서는 선언된 variants 외에도 className을 추가로 받을 수 있습니다. 추가할 className이 없다면 이 부분은 생략하셔도 됩니다.

     

    작성된 Button Component 사용 예제입니다.

    import Button from '@/components/Button';
    
    function Component() {
      return (
        <div className="w-full h-full p-10 space-y-2">
          <Button size="md">btn1</Button>
          <Button className="text-red-600" variant="grey" size="lg">
            btn2
          </Button>
          <Button variant="red" size="xl">
            btn3
          </Button>
        </div>
      );
    }
    
    export default Component;

     

    VSCode 추가 설정

    VSCode에서 Tailwind CSS IntelliSense extension을 사용할 경우 cva 내부에서 작동을 안 하는 것을 확인할 수 있습니다. cva 내부에서 작동할 수 있도록 setting.json에 해당 항목을 추가합니다.

    {
     ...
     "tailwindCSS.experimental.classRegex": [
        ["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"]
      ]
    }

     

    마무리

    Tailwind CSS와 같이 사용할 수 있는 라이브러리 덕분에 Tailwind CSS를 잘 활용할 수 있는 방법이 계속 나오고 있습니다. 이전에는 Styled Components와 Tailwind CSS를 같이 쓰는 방식을 포스팅했었는데 작업 환경에 맞게 여러 방식을 선택하여 사용하면 되겠습니다. 단순히 Tailwind CSS를 쓰는 것에 그치지 않고 좀 더 활용할 수 있는 방안을 계속 찾아봐야겠습니다.


    참고 자료

    https://medium.com/@gorkemkaramolla/react-tailwind-reuseable-and-customizable-components-with-cva-clsx-and-tailwindmerge-combo-guide-c3756bdbbf16

    https://xionwcfm.tistory.com/328

    https://xionwcfm.tistory.com/325

     

    'Style > Libraries' 카테고리의 다른 글

    Styled Components with Tailwind CSS  (0) 2023.09.24
Designed by Tistory.