notes
shadcn/ui
shadcn/ui 컴포넌트 설치·구성 방식과 커스터마이징 메모.
- shadcn/ui는 npm으로 깔는 라이브러리가 아니라, CLI가 컴포넌트 소스를 내 프로젝트에 복사해 주는 방식이다.
- 동작은 Radix, 스타일은 Tailwind라서 복사된 파일을 우리 디자인에 맞게 바로 고칠 수 있다.
- 땡큐처럼 회사 DS 패키지가 이미 있으면 UI 체계가 두 개가 돼서 안 쓴다.
처음엔 turborepo처럼 빌드 도구인 줄 알고 적어 뒀다가, 써 보고 나서 다시 정리했다.
npm 패키지가 아니라, 복사해서 내 프로젝트에 넣는 React UI 컴포넌트 모음 + CLI
헷갈리는 포인트부터
컴포넌트 라이브러리라기보다는 가져다 쓰는 컴포넌트 코드 모음에 가깝다. 그래서 package.json에 shadcn이라는 의존성은 안 생기고, Radix나 cva 같은 밑바닥 패키지만 생긴다.
비유
코드가 내 components/ui/ 폴더에 생기니까 우리 디자인에 맞게 고치는 게 쉽다. 대신 업데이트는 내가 챙겨야 한다. npm update 한 번으로 끝나는 게 아니라, 다시 add해서 바뀐 부분을 보고 내 수정사항과 합친다.
어떻게 쓰나?
npx shadcn@latest init # 프로젝트 설정
npx shadcn@latest add button # Button 컴포넌트 소스 복사
실행하면 이런 파일이 프로젝트 안에 생긴다. init은 components.json(경로, 스타일 설정), lib/utils.ts의 cn(), 전역 CSS의 색 변수를 만들어 주고, add는 컴포넌트 파일을 넣어 준다.
components/ui/button.tsx ← 이게 내 코드
components/ui/dialog.tsx
import { Button } from "@/components/ui/button" 처럼 내 경로에서 import.
기술 스택 (뭘 기반으로 만드나)
shadcn/ui 자체는 얇은 껍데기이고, 실제 동작은 아래 패키지들이 한다.
내 느낌으로는 Radix로 동작하고 Tailwind로 꾸민 컴포넌트 레시피다.
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', {
variants: {
variant: {
default: 'bg-primary text-primary-foreground',
destructive: 'bg-destructive text-white',
outline: 'border bg-background',
},
size: { default: 'h-9 px-4', sm: 'h-8 px-3', lg: 'h-10 px-6' },
},
defaultVariants: { variant: 'default', size: 'default' },
});
export function Button({ className, variant, size, asChild = false, ...props }:
React.ComponentProps<'button'> & VariantProps<typeof buttonVariants> & { asChild?: boolean }) {
const Comp = asChild ? Slot : 'button';
return <Comp className={cn(buttonVariants({ variant, size }), className)} {...props} />;
}새 variant가 필요하면 variants.variant에 한 줄 추가하면 끝이다. asChild를 주면 <Button asChild><Link href="/">홈</Link></Button>처럼 링크에 버튼 스타일만 입힐 수 있다.
일반 UI 라이브러리 vs shadcn
왜 인기 있나?
- 소유권 — 컴포넌트가 내 코드라 마음대로 수정
- Tailwind — 요즘 React 스택과 잘 맞음
- 접근성 — Radix 기반이라 Dialog, Select 등 a11y 기본 탑재
- Next.js — App Router 예제·문서 많음
- 예쁨 — 기본 스타일이 깔끔해서 스타트업·사이드 프로젝트에 많이 씀
신 프로젝트(땡큐)와의 관계
땡큐 모노레포에서는 shadcn/ui를 안 쓴다. 대신 @monorepo/ui가 같은 역할을 한다.
앱마다 <button>을 새로 안 짓고 공통 UI를 쓴다는 개념은 같다. 다만 땡큐는 회사 전용 디자인 시스템을 이미 패키지로 만들어 둔 상태라, shadcn을 더 넣으면 버튼이 두 종류가 되고 팀 규칙과도 안 맞는다.
언제 shadcn을 쓰면 좋나?
자주 나오는 컴포넌트
Button, Input, Dialog, Sheet, Dropdown, Select, Tabs, Toast, Card, Form (react-hook-form + zod 연동) …
한 번에 다 넣지 않고 npx shadcn@latest add xxx로 필요할 때마다 하나씩 넣는다. Form은 react-hook-form과 zod까지 같이 깔리니 참고.
요약
shadcn/ui = Radix + Tailwind로 만든 UI 부품 설명서. npm 라이브러리가 아니라, CLI로 내 프로젝트에 복사해서 쓰고 고치는 방식.