tailwind css 파헤치기 1. 라이브러리 활용편

iberis2·2024년 1월 30일
3

CSS

목록 보기
4/4
post-thumbnail

clsx

조건부 클래스를 표현하는데 용이한 라이브러리

# 설치
$ npm install --dev clsx

사용법

조건부로 클래스 네임을 추가할 때 undefined, null, false 등이 들어갈 수 있는데 자동으로 true 한 string 만 들어가도록 처리해준다.

import clsx from "clsx";

clsx({ foo: true, bar: false, baz: isTrue() });
//=> 'foo baz'

clsx(true, false, "", null, undefined, 0, NaN);
//=> ''

tailwind-merge

클래스이름 중복을 제거해주는 라이브러리

# 설치
npm i -D tailwind-merge

사용법

중복 되는 style 에 대해 뒤에 열거된 style 로 적용해준다.

import { twMerge } from 'tailwind-merge'

twMerge('px-2 py-1 bg-red hover:bg-dark-red', 'p-3 bg-[#B91C1C]')
// → 'hover:bg-dark-red p-3 bg-[#B91C1C]'

prettier-plugin-tailwindcss

클래스 이름을 자동 정렬해주는 라이브러리

# 설치
npm install -D prettier prettier-plugin-tailwindcss

Prettier config 파일의 plugins 배열 가장 마지막에 "prettier-plugin-tailwindcss" 을 추가해줘야 한다.

// .prettierrc 

{
  // ... 생략
  "plugins": [ "prettier-plugin-tailwindcss" ] // 여러 플러그인을 설치했다면 가장 마지막에 적어야 한다
}

prettier 를 적용하면 자동 정렬 된다.
Prettier config 파일에 "tailwindAttributes": ['정렬 기준'] 을 추가해 정렬 기준에 따라 정렬시킬 수도 있다.

class variance authority

컴포넌트의 상태에 따른 스타일을 달리 표현할때 도움이 되는 라이브러리

# 설치
npm i -D class-variance-authority

사용법

1. 컴포넌트

// Button.tsx 컴포넌트

import { ButtonProps } from "./types";
import { buttonStyle } from  "./styles";

export default function Button ({ className, intent, size,  ...props }: ButtonProps) { 

  return <button className={ buttonStyle({ intent, size, className }) } {...props} />;

}

intent, size 에 따라 다른 className을 적용하는 Button 컴포넌트를 만들어보자
intent, size를 props 로 받아서 className 에 cva 로 만든 buttonStyle 함수에 object 형식으로 넘겨준다.

2. 스타일

// styles.ts 

import { cva, type VariantProps } from "class-variance-authority";

export const buttonStyle = cva("button", {
  variants: {
    intent: {
      primary: [ // intnet 가 primary 일 때 적용 될 className
        "bg-blue-500",
        "text-white",
        "border-transparent",
        "hover:bg-blue-600",
      ],
      secondary: [  // intnet 가 secondary 일 때 적용 될 className
        "bg-white",
        "text-gray-800",
        "border-gray-400",
        "hover:bg-gray-100",
      ],
    },
    size: {
      small: ["text-sm", "py-1", "px-2"], // size 가 small 일 때 적용 될 className
      medium: ["text-base", "py-2", "px-4"], // size 가 medium 일 때 적용 될 className
    },
  },
  compoundVariants: [{ intent: "primary", size: "medium", className: "uppercase" }],
  defaultVariants: {
    intent: "primary",
    size: "medium",
  },
});

cva 함수의 첫 번째 인자에는 공통으로 적용할 className을 작성한다.

  • string, string[ ], clsx 타입으로 작성할 수 있다.

두 번째 인자에는 { variants, compoundVariants, defaultVariants } 가 들어갈 수 있다.
variants 에는 className 을 다르게 적용할 값을 key, value 형식으로 작성한다.

  • 복수의 클래스 이름에 대해 string, string[] 타입으로 작성할 수 있다.

    export const buttonStyle = cva("button", {
      variants: {
        intent: {
          primary: "bg-blue-500 text-white border-transparent hover:bg-blue-600",
          secondary: "bg-white text-gray-800 border-gray-400 hover:bg-gray-100",
        },
        size: {
          small: "text-sm py-1 px-2", 
          medium: "text-base py-2 px-4",
        },
      },
    });

    🔗 compoundVariants : 다양한 조건의 조합에 따라 스타일을 적용해야 할 때 사용

    defaultVariants : variants 의 key의 값이 없을 때 기본으로 적용할 값

3. props 타입

import { type VariantProps } from "class-variance-authority";
import { buttonStyle } from "./styles"

// types.ts
export interface ButtonProps
  extends React.ButtonHTMLAttributes<HTMLButtonElement>,
    VariantProps<typeof buttonStyle> { // ⭐️ VariantProps를 확장해서 사용
      /* intent : "primary" | "secondary" | undefined  // VariantProps 에서 정의되어 있으므로 생략할 수 있다. */
    } 

VariantProps 를 확장해서 사용해야 한다.
VariantProps 의 variants 에서 intent, size 를 이미 정의하고 있으므로, props type 에 추가로 작성하지 않아도 된다.

profile
React, Next.js, TypeScript 로 개발 중인 프론트엔드 개발자

0개의 댓글