Javascript/React

shadcn

LSH2118 2025. 5. 11. 17:06

이제까지는 약간 shadcn의 대한 이해가 두루뭉실했는데, 

최근에 이를 활용한 프로젝트를 보니 이해가 단번에 되어서 shadcn을 주제로 블로그 글을 적어보았다


Shadcn

 

 

세련된 디자인과 뛰어난 접근성을 갖춘 컴포넌트 모음, 그리고 코드 배포 플랫폼.
선호하는 프레임워크와 호환되며, 오픈소스로 자유롭게 사용할 수 있습니다.

 

shadcn/ui Radix UITailwind CSS를 사용하여 구축된 복사하여 붙여 넣을 수 있는 재사용 가능한 컴포넌트의 모음이다

 

shadcn/ui는 기존의 컴포넌트 라이브러리(예: MUI, Chakra UI 등)와는 다른 접근 방식을 제공한다
라이브러리를 설치해서 사용하는 것이 아니라, 직접 컴포넌트를 복사해서 프로젝트 안에 구성하게 된다

 

그래서 공식문서를 보면 컴포넌트 라이브러리를 빌드하는 방법이라고 서술되어 있기도 하다

왜 사용할까?

왜 사용하는지 설명하기 전에 먼저 shadcn이 만들어지게 되는 계기를 알아보자

 

기존의 컴포넌트 라이브러리는 프로젝트에 설치하여 불러와서 사용한다

 

이미 만들어지고 확립된 컴포넌트를 가져와 사용하기에,

스타일을 수정하거나, 커스터마이징 하기에 어려움을 느꼈다

 

또한 설치해서 사용하다보니,

라이브러리의 의존성이나, 업데이트 문제에 즉각 반응하기에 어렵다는 단점이 있다

 

그래서 shadcn은 라이브러리 설치에서 가져오는 게 아니라,

npx add를 통해 단순히 원본 코드를 복사해 가져옴으로써

위에서 설명한 스타일 수정이나, 커스터마이징 유연성을 제공한다

 

또한 내가 필요한 컴포넌트들만 가져오기 때문에

다른 설치해서 가져오는 컴포넌트 라이브러리보다\ 가볍게 사용할 수 있다

어떻게 사용할까?

일단 shadcn은 tailwind로 구성되어 있으니 tailwind가 포함된 프로젝트여야 한다

npx shadcn@latest init //shadcn 설치

npx shadcn@latest add COMPONENT // 컴포넌트 불러오기

 

npx add를 통해 불러온 컴포넌트는 component/ui/폴더의 하위에 해당 컴포넌트 파일이 생성된다

src
├── APP
└── COMPONENT
    └── UI
    	├── button.tsx // npx shadcn-ui@latest add button
        └── checkbox.tsx // npx shadcn-ui@latest add checkbox

 

그 후 component를 불러서 사용할 수 있다

import { Button } from "@/components/ui/button";

export default function Home() {
  return (
    <div className=" bg-green-300 w-screen h-screen">
      <Button>
        로그인
      </Button>
    </div>
  );
}

 

CVA

근데 나의 프로젝트에는 버튼이 쓰일 곳이 많이 있는데 그러면 그때마다 일일이 스타일을 변경해서 import 해야 하냐?

 

npx shadcn-ui@latest init 명령어로 설치할 때 같이 설치되는 패키지 중에

class-variance-authority이라는 패키지도 같이 설치된다

 

class-variance-authority는 Tailwind 클래스 조합을 variant/size 등 조건에 따라 설정할 수 있게 해주는 패키지인데, 

이러한 cva를 이용해 shadcn의 컴포넌트 스타일링을 효율적으로 구현할 수 있다

// app/page.tsx

import Button from "@/components/ui/button";

export default function Home() {
  return (
    <div className=" w-screen h-screen bg-white">
      <Button variant="default">default</Button>
      <Button variant="login">Login</Button>
      <Button variant="logout">logout</Button>
      <Button variant="submit">submit</Button>
      <Button variant="submit" size="submit">
        submit
      </Button>
    </div>
  );
}
// component/ui/button.tsx

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

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

const buttonVariants = cva("flex rounded-md justify-center items-center ", {
  variants: {
    variant: {
      default:
        "bg-primary text-primary-foreground shadow-xs hover:bg-primary-100",
      login: "bg-yellow-500 hover:bg-yellow-200",
      logout: "bg-red-500 hover:bg-red-200",
      submit: "bg-green-500 hover:bg-green-200",
    },
    size: {
      default: "h-9 px-4 py-2 ",
      submit: "w-[10rem] h-[2rem]",
    },
  },
  defaultVariants: {
    variant: "default",
    size: "default",
  },
});

function Button({
  className,
  variant,
  size,
  asChild = false,
  ...props
}: React.ComponentProps<"button"> &
  VariantProps<typeof buttonVariants> & { asChild?: boolean }) {
  const Comp = asChild ? Slot : "button";

  return (
    <Comp
      data-slot="button"
      className={cn(buttonVariants({ variant, size, className }))}
      {...props}
    />
  );
}

export default Button;

 

cva를 사용할 때 cva("...", {...}) 형식으로 작성한다

첫 번째 문자열에는 모든 상황에서 공통으로 가지는 스타일을 지정한다

"flex rounded-md justify-center items-center "

 

두변째 객체애는 각각의 스타일을 지정하는데

variants는 객체 안에 스타일이 변경될 조건을 선언한다

defaultVariants는 기본조건을 입력한다

variants: {
    variant: {
        ...
    }, 
    size: {
        ...
    }
}
defaultVariants: {
	...
}

 

해당 조건을 설정하면 컴포넌트의 props를 설정해 준다

function Button({..., variant, size, ...}): VariantProps<typeof buttonVariants>

 

그리고 사용할 때는 조건을 설정해 주면 된다

<Button variant="submit" size="submit">submit</Button>

 

결과

마지막 요소 hover


참고

shadcn 공식문서

shadcn/ui 와 tailwind 라이브러리 함께 사용하기

shadcn/ui 란 무엇일까?

cva로 재사용 가능한 UI 만들기

'Javascript > React' 카테고리의 다른 글

React Hook Form  (0) 2025.03.19
[React]server component  (0) 2025.03.12
[React]React-Markdown  (0) 2024.12.10
[React]심심할땐 뻘짓이지  (0) 2024.11.19
[React]React-Helmet  (0) 2024.11.04