avatar
yoosioff

tawilnd shadcn

May 25
·
11 min read

이전에 내가 알고있던 배경 지식은 vercel 디자인 ai v0이 shadcn/ui 기반인 것만 알고있었다.

부트스트랩 같이 미리 디자인 된 컴포넌트를 제공해주는 라이브러리 같다. 이러한 라이브러리는 수없이 많은데 shadcn을 왜 쓰는지 조사해보겠다.

컴포넌트 라이브러리가 아니다?

공식문서에 보면 처음부터 shadcn을 이렇게 소개한다.

This is NOT a component library.

부트스트랩 처럼 공통 컴포넌트를 지원하는 컴포넌트 라이브러리인줄 알았는데, 컴포넌트 라이브러리가 아니라고 선을 그었다. 그럼 도대체 무엇이 다를까?

shadcn은 이렇게 말한다.

It's a collection of re-usable components that you can copy and paste into your apps.

I mean you do not install it as a dependency. It is not available or distributed via npm.

바로 앱에 복사하여 붙여넣을 수 있고, 재사용성이 가능한 컴포넌트 모음이라는 말이다.

컴포넌트 라이브러리가 아닌 이유는 종속성을 설치하지 않아서 npm을 통해 사용할 수 없거나 배포되지 않는다.

필요한 컴포넌트가 생기면 그에 맞게 코드를 붙여넣고 커스텀을 할 수 있다.

부트 스트랩도 커스텀할 수 있지 않나? 아직은 shadcn에 대한 의문이 생긴다.

부트스트랩 비교

shadcn 사용법을 알기 전에 유사한 라이브러리인 부트스트랩에 대해서 알아보겠다.

부트스트랩이란 미리 만들어진 컴포넌트들을 가져와 사용하는 프레임워크이다.

<link rel="stylesheet" href="<https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css>">

이렇게 cdn을 가져와 그에 맞는 컴포넌트를 복사 혹은 미리 정의된 클래스 이름을 불러와 공통 컴포넌트를 사용한다.

<div class="accordion" id="accordionExample">
  <div class="accordion-item">
    <h2 class="accordion-header" id="headingOne">
      <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
        Accordion Item#1
      </button>
    </h2>
  </div>
</div>

장점

  1. 반응형 지원

  2. 미리 만들어진 컴포넌트를 사용함으로 빠른 개발 시간으로 높은 생산성

단점

  1. 디자인의 개성이 떨어짐

  2. 사용하지 않는 컴포넌트라도 템플릿을 모두 다 가져오기 때문에 낮은 성능

shadcn은 부트스트랩의 가장 큰 단점인 낮은 성능이라는 근본적인 문제를 해결하기 위해 바로 종속성을 없애는 것이다.

그래서 shadcn은 자신을 This is NOT a component library.라고 소개한 것이기도 하다.

자주 묻는 질문

Why copy/paste and not packaged as a dependency?(왜 복사붙여 넣기를 하고, 종속성을 패키지하지 않은 이유는 무엇인가요?)

몇가지의 세팅으로만 통해 필요에 맞는 컴포넌트를 커스텀화 할 수 있기 때문입니다.

Do you plan to publish it as an npm package? (npm패키지로 출시할 계획이 있나요?)

이에 대해서는 shadcn은 단호하게 없다고 한다.

npm으로 출시하면 무슨 단점이 있길래 이렇게 단호하게 말할 수 있는 것일까?

npm패키지로 컴포넌트를 패키징하는 것의 단점 중 하나는 스타일이 구현과 결합된다는 것이다. 컴포넌트의 디자인은 구현과 분리되어야 한다고 주장한다.

설치 & 사용 방법

공식 문서에도 잘 나와있어, 핵심적인 부분만 작성했다.

Next.js Install and configure Next.js. ui.shadcn.com

npx create-next-app@latest my-app --typescript --tailwind --eslint

npx shadcn-ui@latest init

신기하게 명령어를 통해서 컴포넌트를 불러오는 것 같았다.

npm으로 배포하지 않는다는 것을 보고 package.json 파일을 보았는데, shadcn에 대한 명시가 되어있지 않았다.

npx shadcn-ui@latest add button

버튼을 추가하는 명령어를 입력했더니 패키지에 추가되는게 아니라 컴포넌트 폴더 > 파일에 추가되었다.

처음에 컴포넌트들의 스타일이 적용이 안되는 문제가 발생했었는데 tailwind css세팅이 되지 않았다.

import "../app/globals.css";

컴포넌트 파일에 해당 css 파일을 불러오니 해결 되었다.

css 파일에는 다음과 같은 선언이 있었기 때문에 스타일이 적용된다.

@tailwind base;
@tailwind components;
@tailwind utilities;

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",
      },
...
  }
)

export interface ButtonProps
...
}

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}
      />
    )
  }
)
...

이런 식으로 코드가 자동적으로 불러와지는 것을 볼 수 있다.

tailwind와 같이 사용되는 이유?

먼저 처음 생각나는건 zero runtime이기 때문일 것 같다.

server component에서 css in js 라이브러리인 styled-components 나 emotion css를 사용하게 된다면 실행되지 않는다. 왜냐하면 두 라이브러리는 런타임 환경 설정이 필요하기 때문이다.

하지만, tailwind css는 zero run time으로 따로 런타임 환경이 필요하지 않기 때문에 가장 큰 장점으로 보았다.

(”shadcn을 제작한 회사 vercel은 next도 제작하였기 때문에 해당 app dir 환경에서도 돌아갈 수 있도록 구성하기 위해 tailwind를 채택하지 않았을까?” 라고 추측 해보았다.)

추가로 tailwind를 사용하는 이유를 알기 위해서 tailwind의 장점을 찾아보았다.

  • 스타일 클래스의 이름을 생각할 필요가 없습니다.

클래스 이름 자체가 스타일 적용 문법이기 때문에 따로 해당 컴포넌트에 맞는 클래스 이름을 제작할 필요가 없다는 것이다.

  • 스타일 파일과 컴포넌트 구성 파일이 동일합니다.

컴포넌트 제작 파일에서 스타일도 적용하기 때문에 코드 사이의 컨텍스트 전환이 훨씬 적다.

Shadcn/ui를 사용하는 이유

tailwind css를 사용한다면 shadcn/ui를 안쓸 이유가 없다. 별도의 npm 설치가 필요한 것이 아니기 때문에 번들 사이즈가 커지지도 않고, 커스텀하기 쉽기 때문이다.

shadcn이 왜 컴포넌트 라이브러리라고 주장하지 않는지 알 것 같다.

  1. 별도의 설치가 필요 없음

  2. bootstrap은 별도의 스타일 파일이 필요하지만, shadcn은 tailwind 만 있으면 직접 구현 가능

  3. 필요한 구현 부분안 쉽게 가져다 쓰기 때문에 커스텀이 쉬움

우리 회사에서 shadcn을 사용하는 이유?

빠른 개발 생산성이 가장 큰 이유이지 않을까 싶다.

파일 구성도 명령어로 빠르게 가능하고, shadcn이 구성한 디자인이 아니더라도 tailwind css만 알고 있다면 빠르게 커스터마이징이 가능하기 때문에 사용하는 것 같다.

또한 복잡한 구현이 필요한 아코디언, 툴팁, 페이지네이션 등 이러한 컴포넌트를 바로 구현해줄 수 있다. 물론 디자인은 그에 맞게 변경을 해야하지만 shadcn이 구현을 다 해주기 때문에 개발자는 구현보다 스타일에 집중할 수 있다.

Reference

(번역) Tailwind CSS의 장점과 단점

[CSS] 왜 Next.js는 tailwind를 추천할까

shadcn/ui 를 이용한 공유 UI 컴포넌트 사용 경험

부트스트랩 ( bootstrap ) 이란?







안녕하세요 :)