css

shadcn/ui 사용법 익히기

냠냠맨 2023. 8. 21. 12:20

shadcn/ui

https://ui.shadcn.com/docs

 

Introduction

Re-usable components built using Radix UI and Tailwind CSS.

ui.shadcn.com

shadcn/ui는 Radix UI와 tailwindcss를 기반으로 빌드된 컴포넌트 모음집입니다.

toast와 같은 ui 기능들은 Radix ui 에서 가져와 사용하고

tailwindcss와 내부적으로는 tailwind-merge , clsx, cva를 이용하여

즉시 사용할 수 있는 아톰컴포넌트들을 제공합니다.

tailwindcss 계의 mui 같은 느낌이라고 생각할 수도 있을 것 같네요

 

다만 nodemodules에서 컴포넌트들이 관리되는 것이 아니라

커스터마이징이 훨씬 간편하다는 장점이 있습니다.

실제로도 shadcn/ui는 종속성으로 관리하는 것이 아닌 복사/ 붙여넣기를 통한 관리를 권장합니다

 

아톰컴포넌트의 스타일링을 하는 것은 상당히 지루한 일인데에 반하여

일반적으로 사용하는 디자인들은 어느정도 유사성이 있으니

그러한 반복적인 작업들을 효율화 시켜주는 라이브러리라고 생각할 수 있습니다.

 

이번에는 next.js에서의 사용례를 알아봅니다.


how to use?

npx shadcn-ui@latest init

위 명령어를 입력하면 shadcn-ui를 사용하기 위한 설정에 대한 질문을 받습니다.

Would you like to use TypeScript (recommended)? no / yes
Which style would you like to use? › Default
Which color would you like to use as base color? › Slate
Where is your global CSS file? › › app/globals.css
Do you want to use CSS variables for colors? › no / yes
Where is your tailwind.config.js located? › tailwind.config.js
Configure the import alias for components: › @/components
Configure the import alias for utils: › @/lib/utils
Are you using React Server Components? › no / yes

적절히 자신의 상황에 맞는 답변들을 골라주면 되겠습니다.

저는 tailwind.config.js 대신 .ts를 사용하고 있어서 그 부분을 고쳐줬습니다.

init을 마치고나면

component.json , tailwind.config.js , utils 등의 파일이 생성되거나 변경됩니다.

npx shadcn-ui@latest add button

 

원하는 아이템을 추가합니다.

import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"

import { cn } from "@/lib/utils"

const buttonVariants = cva(
  "inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-white transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-950 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 dark:ring-offset-slate-950 dark:focus-visible:ring-slate-300",
  {
    variants: {
      variant: {
        default: "bg-slate-900 text-slate-50 hover:bg-slate-900/90 dark:bg-slate-50 dark:text-slate-900 dark:hover:bg-slate-50/90",
        destructive:
          "bg-red-500 text-slate-50 hover:bg-red-500/90 dark:bg-red-900 dark:text-slate-50 dark:hover:bg-red-900/90",
        outline:
          "border border-slate-200 bg-white hover:bg-slate-100 hover:text-slate-900 dark:border-slate-800 dark:bg-slate-950 dark:hover:bg-slate-800 dark:hover:text-slate-50",
        secondary:
          "bg-slate-100 text-slate-900 hover:bg-slate-100/80 dark:bg-slate-800 dark:text-slate-50 dark:hover:bg-slate-800/80",
        ghost: "hover:bg-slate-100 hover:text-slate-900 dark:hover:bg-slate-800 dark:hover:text-slate-50",
        link: "text-slate-900 underline-offset-4 hover:underline dark:text-slate-50",
      },
      size: {
        default: "h-10 px-4 py-2",
        sm: "h-9 rounded-md px-3",
        lg: "h-11 rounded-md px-8",
        icon: "h-10 w-10",
      },
    },
    defaultVariants: {
      variant: "default",
      size: "default",
    },
  }
)

export interface ButtonProps
  extends React.ButtonHTMLAttributes<HTMLButtonElement>,
    VariantProps<typeof buttonVariants> {
  asChild?: boolean
}

const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
  ({ className, variant, size, asChild = false, ...props }, ref) => {
    const Comp = asChild ? Slot : "button"
    return (
      <Comp
        className={cn(buttonVariants({ variant, size, className }))}
        ref={ref}
        {...props}
      />
    )
  }
)
Button.displayName = "Button"

export { Button, buttonVariants }

cva에 익숙한 분들은 직접 작성하던 컴포넌트와 차이를 느끼기 힘든 코드입니다.

다만 귀찮게 작성해줘야했던 forwardRef 처리 , children 처리 등이 모두 완료되어있어

매우 사용성이 좋습니다.


toast 사용해보기

npx shadcn-ui@latest add toast

토스트의 경우에는 사용방법이 조금 다릅니다.

위 명령어를 입력하고나면 toast, toaster , use-toast 세개의 파일이 생성됩니다.

toast - toast 컴포넌트의 디자인을 담당합니다. 컴포넌트입니다.

toaster - 컨테이너의 역할을 수행합니다. 컴포넌트입니다.

use-toast - 커스텀훅으로 실제 로직은 여기에 다 들어있습니다.

우선 toaster 컴포넌트를 앱의 최상단에 렌더링시킵니다.

next.js의 경우에는 최상위의 layout.tsx 파일이 됩니다.

const ToastComponent = ({}:ToastComponentProps) => {
  const {toast} = useToast()
 return <div>
    <button onClick={() => toast({title:'hi', description:'설명입니다.', variant:'default'})} >토스트버튼</button>
 </div>
}

기본적인 사용 예시는 다음과 같습니다.

이후 필요한만큼 커스터마이징하면 됩니다.

const TOAST_LIMIT = 2
const TOAST_REMOVE_DELAY = 1000000

use-toast 파일의 두 변수 값을 조정하는 것을 통해 토스트의 갯수와 딜레이를 조절할 수 있습니다.

 

반응형