shadcn/ui
CLI를 통해 사용자 프로젝트에 컴포넌트를 소스 코드로 추가하여 UI, 컴포넌트 및 디자인 시스템을 구축하기 위한 프레임워크입니다.
중요: 모든 CLI 명령어는 프로젝트의 패키지 러너(
npx shadcn@latest,pnpm dlx shadcn@latest, 또는bunx --bun shadcn@latest— 프로젝트의packageManager기준)를 사용하여 실행하세요. 아래 예시는npx shadcn@latest를 사용하지만 프로젝트에 맞는 올바른 러너로 대체하세요.
현재 프로젝트 컨텍스트
!`npx shadcn@latest info --json`
위 JSON에는 프로젝트 설정과 설치된 컴포넌트가 포함되어 있습니다. npx shadcn@latest docs <component>를 사용하여 모든 컴포넌트에 대한 문서 및 예제 URL을 가져올 수 있습니다.
원칙
- 기존 컴포넌트를 먼저 사용하세요. 커스텀 UI를 작성하기 전에
npx shadcn@latest search를 사용하여 레지스트리를 확인하세요. 커뮤니티 레지스트리도 확인하세요. - 조합하되, 재발명하지 마세요. 설정 페이지 = Tabs + Card + form controls. 대시보드 = Sidebar + Card + Chart + Table.
- 커스텀 스타일보다 내장된 변형을 사용하세요.
variant="outline",size="sm"등. - 시맨틱 색상을 사용하세요.
bg-primary,text-muted-foreground—bg-blue-500과 같은 원시 값은 절대 사용하지 마세요.
중요 규칙
이 규칙들은 항상 적용됩니다. 각 규칙은 잘못된/올바른 코드 쌍이 있는 파일에 연결됩니다.
스타일링 & Tailwind → styling.md
- 레이아웃에는
className사용, 스타일링에는 사용하지 마세요. 컴포넌트 색상이나 타이포그래피를 절대 재정의하지 마세요. space-x-*또는space-y-*사용 금지.flex와gap-*를 사용하세요. 수직 스택의 경우flex flex-col gap-*를 사용하세요.- 너비와 높이가 같을 때
size-*를 사용하세요.size-10(올바름),w-10 h-10(틀림) truncate단축어를 사용하세요.overflow-hidden text-ellipsis whitespace-nowrap대신 사용하세요.- 수동
dark:색상 재정의 금지. 시맨틱 토큰(bg-background,text-muted-foreground)을 사용하세요. - 조건부 클래스에는
cn()을 사용하세요. 수동 템플릿 리터럴 삼항 연산자를 작성하지 마세요. - 오버레이 컴포넌트에 수동
z-index금지. Dialog, Sheet, Popover 등은 자체적으로 스태킹을 처리합니다.
폼 및 입력 → forms.md
- 폼은
FieldGroup+Field를 사용합니다. 폼 레이아웃에 원시div와space-y-*또는grid gap-*를 절대 사용하지 마세요. InputGroup은InputGroupInput/InputGroupTextarea를 사용합니다.InputGroup내부에 원시Input/Textarea를 절대 사용하지 마세요.- 입력 내부의 버튼은
InputGroup+InputGroupAddon을 사용합니다. - 옵션 세트(2~7개 선택지)는
ToggleGroup을 사용합니다. 수동 활성 상태로Button을 반복하지 마세요. - 관련 체크박스/라디오 그룹화에는
FieldSet+FieldLegend를 사용합니다. 제목이 있는div를 사용하지 마세요. - 필드 유효성 검사는
data-invalid+aria-invalid를 사용합니다.Field에는data-invalid, 컨트롤에는aria-invalid. 비활성화된 경우:Field에data-disabled, 컨트롤에disabled.
컴포넌트 구조 → composition.md
- 항목은 항상 해당 그룹 내부에 있어야 합니다.
SelectItem→SelectGroup.DropdownMenuItem→DropdownMenuGroup.CommandItem→CommandGroup. - 커스텀 트리거에는
asChild(radix) 또는render(base)를 사용하세요.npx shadcn@latest info에서base필드를 확인하세요. → base-vs-radix.md - Dialog, Sheet, Drawer는 항상 Title이 필요합니다. 접근성을 위해
DialogTitle,SheetTitle,DrawerTitle이 필요합니다. 시각적으로 숨기려면className="sr-only"를 사용하세요. - 전체 Card 구성을 사용하세요.
CardHeader/CardTitle/CardDescription/CardContent/CardFooter. 모든 것을CardContent에 넣지 마세요. - Button에는
isPending/isLoading이 없습니다.Spinner+data-icon+disabled로 구성하세요. TabsTrigger는TabsList내부에 있어야 합니다. 트리거를Tabs에 직접 렌더링하지 마세요.Avatar는 항상AvatarFallback이 필요합니다. 이미지 로드 실패 시备用입니다.
컴포넌트 사용, 커스텀 마크업 사용 금지 → composition.md
- 커스텀 마크업보다 기존 컴포넌트를 먼저 사용하세요. 스타일이 지정된
div를 작성하기 전에 컴포넌트가 존재하는지 확인하세요. - 콜아웃은
Alert를 사용하세요. 커스텀 스타일 div를 만들지 마세요. - 빈 상태는
Empty를 사용하세요. 커스텀 빈 상태 마크업을 만들지 마세요. - Toast는
sonner를 통해 사용하세요.sonner의toast()를 사용하세요. Separator를 사용하세요.<hr>또는<div className="border-t">대신.- 로딩 플레이스홀더에는
Skeleton을 사용하세요. 커스텀animate-pulsediv를 사용하지 마세요. Badge를 사용하세요. 커스텀 스타일 span 대신.
아이콘 → icons.md
Button내의 아이콘은data-icon을 사용합니다. 아이콘에data-icon="inline-start"또는data-icon="inline-end"를 사용하세요.- 컴포넌트 내부의 아이콘에 크기 클래스를 사용하지 마세요. 컴포넌트는 CSS를 통해 아이콘 크기를 처리합니다.
size-4또는w-4 h-4사용 금지. - 아이콘을 문자열 키가 아닌 객체로 전달하세요.
icon={CheckIcon}, 문자열 조회 금지.
CLI
- 프리셋 코드를 수동으로 디코딩하거나 가져오지 마세요.
npx shadcn@latest init --preset <code>에 직접 전달하세요.
주요 패턴
다음은 올바른 shadcn/ui 코드를 구분하는 가장 일반적인 패턴입니다. 에지 케이스는 위에 링크된 규칙 파일을 참조하세요.
// 폼 레이아웃: FieldGroup + Field, div + Label 사용 금지.
<FieldGroup>
<Field>
<FieldLabel htmlFor="email">이메일</FieldLabel>
<Input id="email" />
</Field>
</FieldGroup>
// 유효성 검사: Field에는 data-invalid, 컨트롤에는 aria-invalid.
<Field data-invalid>
<FieldLabel>이메일</FieldLabel>
<Input aria-invalid />
<FieldDescription>유효하지 않은 이메일입니다.</FieldDescription>
</Field>
// 버튼 내 아이콘: data-icon, 크기 클래스 없음.
<Button>
<SearchIcon data-icon="inline-start" />
검색
</Button>
// 간격: gap-*, space-y-* 사용 금지.
<div className="flex flex-col gap-4"> // 올바름
<div className="space-y-4"> // 틀림
// 동일한 치수: size-*, w-* h-* 사용 금지.
<Avatar className="size-10"> // 올바름
<Avatar className="w-10 h-10"> // 틀림
// 상태 색상: Badge 변형 또는 시맨틱 토큰, 원시 색상 사용 금지.
<Badge variant="secondary">+20.1%</Badge> // 올바름
<span className="text-emerald-600">+20.1%</span> // 틀림
컴포넌트 선택
| 필요 사항 | 사용 |
|---|---|
| 버튼/액션 | 적절한 variant와 함께 Button 사용 |
| 폼 입력 | Input, Select, Combobox, Switch, Checkbox, RadioGroup, Textarea, InputOTP, Slider |
| 2~5개 옵션 전환 | ToggleGroup + ToggleGroupItem 사용 |
| 데이터 표시 | Table, Card, Badge, Avatar 사용 |
| 네비게이션 | Sidebar, NavigationMenu, Breadcrumb, Tabs, Pagination 사용 |
| 오버레이 | Dialog (모달), Sheet (사이드 패널), Drawer (바텀 시트), AlertDialog (확인) 사용 |
| 피드백 | sonner (토스트), Alert, Progress, Skeleton, Spinner 사용 |
| 명령 팔레트 | Dialog 내 Command 사용 |
| 차트 | Chart (Recharts 래핑) 사용 |
| 레이아웃 | Card, Separator, Resizable, ScrollArea, Accordion, Collapsible 사용 |
| 빈 상태 | Empty 사용 |
| 메뉴 | DropdownMenu, ContextMenu, Menubar 사용 |
| 툴팁/정보 | Tooltip, HoverCard, Popover 사용 |
주요 필드
주입된 프로젝트 컨텍스트에는 다음과 같은 주요 필드가 포함됩니다:
aliases→ 가져오기에 실제 별칭 접두사(예:@/,~/)를 사용하고, 하드코딩하지 마세요.isRSC→true인 경우,useState,useEffect, 이벤트 핸들러 또는 브라우저 API를 사용하는 컴포넌트는 파일 상단에"use client"가 필요합니다. 지시문에 대해 조언할 때 항상 이 필드를 참조하세요.tailwindVersion→"v4"는@theme inline블록을 사용하고,"v3"는tailwind.config.js를 사용합니다.tailwindCssFile→ 커스텀 CSS 변수가 정의된 전역 CSS 파일입니다. 항상 이 파일을 편집하고 새 파일을 만들지 마세요.style→ 컴포넌트 시각적 처리(예:nova,vega).base→ 프리미티브 라이브러리(radix또는base). 컴포넌트 API 및 사용 가능한 props에 영향을 줍니다.iconLibrary→ 아이콘 가져오기를 결정합니다.lucide의 경우lucide-react,tabler의 경우@tabler/icons-react등을 사용하세요.lucide-react를 가정하지 마세요.resolvedPaths→ 컴포넌트, 유틸리티, 훅 등의 정확한 파일 시스템 대상입니다.framework→ 라우팅 및 파일 규칙(예: Next.js App Router vs Vite SPA).packageManager→ shadcn이 아닌 종속성 설치에 사용하세요(예:pnpm add date-fnsvsnpm install date-fns).
전체 필드 참조는 cli.md — info 명령어를 참조하세요.
컴포넌트 문서, 예제 및 사용법
npx shadcn@latest docs <component>를 실행하여 컴포넌트의 문서, 예제 및 API 참조 URL을 가져오세요. 실제 콘텐츠를 얻으려면 이 URL을 가져오세요.
npx shadcn@latest docs button dialog select
컴포넌트를 생성, 수정, 디버깅 또는 사용할 때는 항상 먼저 npx shadcn@latest docs를 실행하고 URL을 가져오세요. 이렇게 하면 추측하는 대신 올바른 API 및 사용 패턴으로 작업할 수 있습니다.
워크플로우
- 프로젝트 컨텍스트 가져오기 — 위에 이미 주입되었습니다. 새로고침이 필요하면
npx shadcn@latest info를 다시 실행하세요. - 먼저 설치된 컴포넌트 확인 —
add를 실행하기 전에 항상 프로젝트 컨텍스트의components목록을 확인하거나resolvedPaths.ui디렉토리를 나열하세요. 추가되지 않은 컴포넌트를 가져오지 말고, 이미 설치된 컴포넌트를 다시 추가하지 마세요. - 컴포넌트 찾기 —
npx shadcn@latest search. - 문서 및 예제 가져오기 —
npx shadcn@latest docs <component>를 실행하여 URL을 가져온 다음 가져오세요.npx shadcn@latest view를 사용하여 설치하지 않은 레지스트리 항목을 탐색하세요. 설치된 컴포넌트의 변경 사항을 미리 보려면npx shadcn@latest add --diff를 사용하세요. - 설치 또는 업데이트 —
npx shadcn@latest add. 기존 컴포넌트를 업데이트할 때는 먼저--dry-run및--diff를 사용하여 변경 사항을 미리 보세요(아래 컴포넌트 업데이트 참조). - 타사 컴포넌트에서 가져오기 수정 — 커뮤니티 레지스트리(예:
@bundui,@magicui)에서 컴포넌트를 추가한 후, 추가된 비 UI 파일에서@/components/ui/...와 같은 하드코딩된 import 경로가 있는지 확인하세요. 이는 프로젝트의 실제 별칭과 일치하지 않을 수 있습니다.npx shadcn@latest info를 사용하여 올바른ui별칭(예:@workspace/ui/components)을 가져오고 그에 따라 import를 다시 작성하세요. CLI는 자체 UI 파일의 import를 다시 작성하지만, 타사 레지스트리 컴포넌트는 프로젝트와 일치하지 않는 기본 경로를 사용할 수 있습니다. - 추가된 컴포넌트 검토 — 모든 레지스트리에서 컴포넌트 또는 블록을 추가한 후, 항상 추가된 파일을 읽고 올바른지 확인하세요. 누락된 하위 컴포넌트(예:
SelectGroup없이SelectItem), 누락된 import, 잘못된 구성 또는 중요 규칙 위반이 있는지 확인하세요. 또한 아이콘 import를 프로젝트 컨텍스트의iconLibrary로 바꾸세요(예: 레지스트리 항목이lucide-react를 사용하지만 프로젝트가hugeicons를 사용하는 경우 import와 아이콘 이름을 교체하세요). 진행하기 전에 모든 문제를 해결하세요. - 레지스트리는 명시적이어야 함 — 사용자가 블록 또는 컴포넌트 추가를 요청할 때 레지스트리를 추측하지 마세요. 레지스트리가 지정되지 않은 경우(예: 사용자가
@shadcn,@tailark등을 지정하지 않고 "로그인 블록 추가"라고 말하는 경우), 사용할 레지스트리를 물어보세요. 사용자를 대신하여 레지스트리를 기본값으로 설정하지 마세요. - 프리셋 전환 — 먼저 사용자에게 재설치, 병합 또는 건너뛰기 중 무엇을 할지 물어보세요.
- 재설치:
npx shadcn@latest init --preset <code> --force --reinstall. 모든 컴포넌트를 덮어씁니다. - 병합:
npx shadcn@latest init --preset <code> --force --no-reinstall을 실행한 다음,npx shadcn@latest info를 실행하여 설치된 컴포넌트를 나열하고, 각 설치된 컴포넌트에 대해--dry-run및--diff를 사용하여 개별적으로 스마트 병합을 수행합니다. - 건너뛰기:
npx shadcn@latest init --preset <code> --force --no-reinstall. 설정과 CSS만 업데이트하고 컴포넌트는 그대로 둡니다. - 중요: 프리셋 명령어는 항상 사용자의 프로젝트 디렉토리 내에서 실행하세요. CLI는
components.json의 현재 베이스(basevsradix)를 자동으로 유지합니다. 스크래치/임시 디렉토리(예:--dry-run비교용)를 사용해야 하는 경우--base <current-base>를 명시적으로 전달하세요. 프리셋 코드는 베이스를 인코딩하지 않습니다.
- 재설치:
컴포넌트 업데이트
사용자가 로컬 변경 사항을 유지하면서 업스트림에서 컴포넌트를 업데이트하도록 요청하는 경우 --dry-run 및 --diff를 사용하여 지능적으로 병합하세요. GitHub에서 원시 파일을 수동으로 가져오지 마세요. 항상 CLI를 사용하세요.
npx shadcn@latest add <component> --dry-run을 실행하여 영향을 받는 모든 파일을 확인합니다.- 각 파일에 대해
npx shadcn@latest add <component> --diff <file>을 실행하여 업스트림과 로컬이 어떻게 변경되었는지 확인합니다. - diff를 기반으로 파일별로 결정합니다.
- 로컬 변경 사항 없음 → 덮어쓰기 안전.
- 로컬 변경 사항 있음 → 로컬 파일을 읽고 diff를 분석한 후 로컬 수정 사항을 유지하면서 업스트림 업데이트를 적용합니다.
- 사용자가 "그냥 모두 업데이트"라고 말하면
--overwrite를 사용하지만, 먼저 확인합니다.
- 사용자의 명시적 승인 없이
--overwrite를 사용하지 마세요.
빠른 참조
# 새 프로젝트를 만듭니다.
npx shadcn@latest init --name my-app --preset base-nova
npx shadcn@latest init --name my-app --preset a2r6bw --template vite
# 모노레포 프로젝트를 만듭니다.
npx shadcn@latest init --name my-app --preset base-nova --monorepo
npx shadcn@latest init --name my-app --preset base-
…
[번역을 위해 잘림]