복붙으로 완성되는 UI: Shadcn UI

최근에 여러 사이드 프로젝트(파크골프가자, nomorebg) 를 하면서 하면서 해외에서 핫한 shadcn을 접하게 되었고, 기존의 어떤 프로젝트보다 빠르게 웹 UI를 구성할 수 있었습니다. shadcn이 갖고 있는 몇가지 특징과 그리고 한계에 대해서 알아보도록 하겠습니다.
Nov 06, 2023
복붙으로 완성되는 UI: Shadcn UI
최근에 여러 사이드 프로젝트(파크골프가자, nomorebg) 를 하면서 하면서 해외에서 핫한 shadcn을 접하게 되었고, 기존의 어떤 프로젝트보다 빠르게 웹 UI를 구성할 수 있었습니다. shadcn이 갖고 있는 몇가지 특징과 그리고 한계에 대해서 알아보도록 하겠습니다.

Shadcn UI의 주요 특징

  • tailwind 기반의 UI
    • shadcn은 tailwind 라이브러리와 Next.js에서 유지보수하고 있는 Radix UI를 결합하여 만들었습니다. 그래서 UI를 수정하거나 사용하려면 기본적인 tailwind 지식이 필수로 필요합니다.
  • 사전 제작된 많은 UI 컴포넌트
    • radix UI를 기초로 한 40종에 가까운 컴포넌트를 제공하며, 필요에 따라 추가적인 스타일링 없이 사용이 가능합니다.
  • 기존의 UI 라이브러리와 차별화된 개발 경험
    • Shadcn은 CLI를 통해서 컴포넌트를 나의 프로젝트에 붙어넣기를 하고, 내가 원하는 형태로 변경하여 사용할 수 있습니다.
  • theming 및 다크모드 지원
    • tailwind theme를 기반으로 손쉽게 전체 프로젝트의 theme를 변경할 수 있으며 또한 dark mode 지원이 가능합니다.

사용 방법

아래의 내용은 Next.js를 기반으로 하며, shadcn은 Next.js 뿐만 아니라 Remix, React, Gatby등을 지원하며 자세한 정보는 링크에서 확인 하실 수 있습니다.

필요한 패키지 설치하기

기본적으로 shadcn이 구동하는데 필요한 라이브러리들을 설치합니다.
npx create-next-app@latest my-app --typescript --tailwind --eslint

CLI 실행하기

shadcn의 최초 설정을 진행합니다.
npx shadcn-ui@latest init

components.json 생성하기

init을 진행하면 아래와 프로젝트 내에서 shadcn을 어떻게 사용할지 설정 할 수 있습니다.
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
위에서 설정된 내용들은 언제든이 component.json 파일에서 바꿀 수 있으니, 내용이 이해되지 않더라도 큰 걱정하지 않으셔도 됩니다. style과 color의 차이는 링크에서 확인 하실 수 있습니다.

생성된 directory 구조 분석

. ├── app │ ├── layout.tsx │ └── page.tsx ├── components │ ├── ui │ │ ├── button.tsx ├── lib │ └── utils.ts ├── styles │ └── globals.css ├── next.config.js ├── package.json ├── postcss.config.js ├── tailwind.config.js └── tsconfig.json
  • CLI를 통해서 설치되는 컴포넌트는 components/ui 아래에 위치 하게 됩니다.
  • lib 폴더에는 tailwind 스타일을 관리할 때 사용되는 util함수가 생성됩니다.
  • styles/globals.css 에는 shadcn을 사용하기 위한 글로벌 스타일들이 저장 됩니다.

컴포넌트 설치하기

npx shadcn-ui@latest add button
위 명령어를 실행하면 아래와 같이 components/ui 폴더에 button 컴포넌트가 생성됩니다.
. ├── app │ ├── layout.tsx │ └── page.tsx ├── components │ ├── ui │ │ ├── button.tsx ├── lib │ └── utils.ts ├── styles │ └── globals.css ├── next.config.js ├── package.json ├── postcss.config.js ├── tailwind.config.js └── tsconfig.json
정확하게 이야기하면, 컴포넌트를 설치한다기 보단 컴포넌트를 복사 붙여넣기에 가깝습니다. 즉, 실제 코드가 button 파일의 이름으로 아래와 같은 코드가 생성이 됩니다.
// 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 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", { variants: { variant: { default: "bg-primary text-primary-foreground hover:bg-primary/90", destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90", outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground", secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80", ghost: "hover:bg-accent hover:text-accent-foreground", link: "text-primary underline-offset-4 hover:underline", }, 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 }
이 코드는 처음에 component.json 을 어떻게 구성했느냐에 따라 달라지기 때문에, 위와 100% 같지 않을 수 있습니다.

컴포넌트 사용하기

import { Button } from "@/components/ui/button" export default function Home() { return ( <div> <Button>Click me</Button> </div> ) }
사용하는 방법은 간단합니다. 다른 컴퍼넌트들처럼 Import하여 쉽게 사용할 수 있습니다.

장단점 분석

3달간 써보면서 느꼈던 장단점을 정리해보겠습니다.

장점

  • 컴포넌트 전체가 내 소스코드에 복사되기 때문에, Props를 추가하거나, 스타일 변경을 쉽게 할 수 있습니다. 추가적인 랩핑 컴포넌트가 필요 없습니다.
  • 40여개의 사전 제작된 컴포넌트를 통해서 빠른 속도로 프로토타이핑을 할 수 있습니다
  • 테마가 제공되어 내가 원하는 무드로 변경이 가능합니다.

단점

  • 모든 스타일링이 tailwind를 통해서 이뤄지므로 tailwind에 대한 사전지식이 필요합니다.
  • 빠른 속도로 성장하고 있는 것은 맞으나, 타 UI 라이브러리 대비해서 자료가 많이 부족합니다.
 

shadcn으로 진행하고 있는 사이드 프로젝트

결론

  • MUI를 사용한 다른 프로젝트와 대비해서 shadcn을 활용하면 커스텀이 쉽고, 직관적인 이해가 되기 때문에 정말 빠르게 만들 수 있습니다. MUI는 각 API Spec을 이해하는데 시간이 많이 소요되었었습니다.
  • t3 stack(next.js, tailwind, typescript)를 사용한다면, 강력하게 추천드립니다.
 
최근에 패스트 캠퍼스에서 NextJS 14, Supabase, Shadcn을 바탕으로 강의를 하게 되었습니다. 블로그에서 언급한 내용들을 대부분 다루고 있고, 제가 가진 모든 노하우를 집약해서 만들고 있습니다. 아래 링크를 통해서 등록하시면 20% 할인 가능하오니, 많은 관심 부탁드려요 https://abit.ly/vbqkjk
Share article

indietools