Shadcn UI · 주요 컴포넌트
Shadcn UI? 가 제공하는 컴포넌트? 들을 분류해서 한눈에 보고, 자주 쓰는 것은 실제 TSX 코드와 "모양 미리보기"로 익힙니다. 모두 헤드리스 프리미티브 위에 Tailwind? 스타일을 입힌 부품들이에요.
이 프로젝트는 shadcn 3.7.0 CLI로 컴포넌트를 복사해 씁니다.
shadcn 컴포넌트는 접근성 좋은 헤드리스 프리미티브 위에 만들어지는데, shadcn의 전통(기본) 기반은 Radix UI이지만
이 프로젝트는 그 후속인 Base UI(@base-ui/react)를 씁니다 — components.json 의 style 값이 base-vega(= Base UI 기반)이기 때문이에요.
실제로 src/components/ui/ 의 컴포넌트 대부분이 @base-ui/react/* 에서 프리미티브를 import 합니다(일부 @radix-ui/react-slot·label 만 잔존).
아이콘은 lucide-react, 코드는 React? + TSX. 아래 표의 "기반 프리미티브" 열은 프리미티브 이름(Dialog·Popover·Select 등)으로, 이 이름들은 Radix와 Base UI에서 거의 동일하게 대응됩니다.
1. 폼 입력 컴포넌트
사용자에게 값을 받는 부품들입니다. 버튼·입력칸·선택지처럼 손이 가장 많이 가는 그룹이에요.
| 컴포넌트 | 용도 | 기반 프리미티브 |
|---|---|---|
Button | 클릭 동작 버튼(변형·크기 다양) | react-slot |
Input | 한 줄 텍스트 입력칸 | 순수 HTML input |
Textarea | 여러 줄 텍스트 입력 | 순수 HTML textarea |
Label | 입력칸에 붙는 이름표 | react-label |
Checkbox | 체크 on/off | react-checkbox |
RadioGroup | 여럿 중 하나 선택 | react-radio-group |
Switch | 토글 스위치(켜짐/꺼짐) | react-switch |
Select | 드롭다운 선택 상자 | react-select |
Slider | 값을 끌어 조절하는 막대 | react-slider |
Toggle | 눌러서 활성/비활성 전환 | react-toggle |
Form | 폼 검증·에러 표시 묶음 | react-hook-form? + Label |
2. 오버레이 컴포넌트
화면 위에 떠서 잠깐 나타나는 부품들입니다. 팝업·메뉴·말풍선이 여기에 속해요.
| 컴포넌트 | 용도 | 기반 프리미티브 |
|---|---|---|
Dialog | 가운데 뜨는 모달 창 | react-dialog |
AlertDialog | 확인/취소를 강제하는 경고 모달 | react-alert-dialog |
Sheet | 옆/위에서 미끄러져 나오는 패널 | react-dialog |
Popover | 버튼 옆에 붙는 작은 팝업 | react-popover |
HoverCard | 마우스 올리면 뜨는 카드 | react-hover-card |
Tooltip | 마우스 올리면 뜨는 작은 설명 | react-tooltip |
DropdownMenu | 버튼 누르면 펼쳐지는 메뉴 | react-dropdown-menu |
ContextMenu | 우클릭으로 뜨는 메뉴 | react-context-menu |
Command | 검색형 명령 팔레트 | cmdk |
3. 표시 컴포넌트
정보를 보여주고 담는 그릇 같은 부품들입니다. 카드·표·탭으로 내용을 정리해요.
| 컴포넌트 | 용도 | 기반 프리미티브 |
|---|---|---|
Card | 제목·내용·버튼을 담는 카드 박스 | 순수 HTML? + Tailwind |
Avatar | 프로필 이미지(없으면 글자) | react-avatar |
Badge | 상태·개수를 표시하는 작은 라벨 | 순수 HTML + Tailwind |
Separator | 구분선(가로/세로) | react-separator |
ScrollArea | 예쁜 커스텀 스크롤 영역 | react-scroll-area |
Tabs | 탭으로 화면 전환 | react-tabs |
Accordion | 접었다 펴는 목록 | accordion |
Collapsible | 한 영역 접기/펴기 | react-collapsible |
Table | 표(행·열) 골격 | 순수 HTML table |
4. 내비게이션 · 피드백 컴포넌트
이동을 돕거나(내비) 결과를 알려주는(피드백) 부품들입니다.
| 컴포넌트 | 용도 | 기반 프리미티브 |
|---|---|---|
NavigationMenu | 상단 메뉴바(하위 메뉴 펼침) | react-navigation-menu |
Breadcrumb | 현재 위치 경로 표시 | 순수 HTML + Tailwind |
Toast | 잠깐 떴다 사라지는 알림 | react-toast |
Sonner | Toast 대체 — 더 간단한 알림 | sonner 라이브러리 |
Skeleton | 로딩 중 자리표시(뼈대) UI | 순수 HTML + Tailwind |
둘 다 "잠깐 뜨는 알림"입니다. 공식 문서는 이제 더 간단한 Sonner 사용을 권합니다.
이 프로젝트도 sonner 패키지가 설치돼 있어, 보통 toast("저장됨") 한 줄로 알림을 띄워요.
5. 대표 사용 예 (TSX)
자주 쓰는 컴포넌트의 실제 코드입니다. import 경로는 모두 @/components/ui/... 로 시작해요(복사된 내 코드 위치).
Button — variant · size
import { Button } from "@/components/ui/button"
function Toolbar() {
return (
<div className="flex gap-2">
<Button>기본</Button>
<Button variant="outline">테두리</Button>
<Button variant="destructive">삭제</Button>
<Button variant="ghost" size="sm">작게</Button>
</div>
)
}variant: default · outline · ghost · destructive · secondary · link / size: xs · sm · default · lg · icon 계열.
Input + Label
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
function NameField() {
return (
<div className="grid gap-1.5">
<Label htmlFor="name">이름</Label>
<Input id="name" placeholder="이름을 입력" />
</div>
)
}Card — Header · Title · Content · Footer
import { Card, CardHeader, CardTitle, CardContent, CardFooter } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
function Profile() {
return (
<Card>
<CardHeader>
<CardTitle>프로필</CardTitle>
</CardHeader>
<CardContent>경수 / 관리자</CardContent>
<CardFooter>
<Button variant="outline">수정</Button>
</CardFooter>
</Card>
)
}Dialog — 트리거 + 콘텐츠
import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog"
import { Button } from "@/components/ui/button"
function Confirm() {
return (
<Dialog>
<DialogTrigger asChild>
<Button>열기</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>정말 삭제할까요?</DialogTitle>
</DialogHeader>
</DialogContent>
</Dialog>
)
}asChild 는 "내 버튼을 트리거로 그대로 써라"라는 뜻이에요(추가 태그 없이 감싼 자식을 트리거로 사용).
Select
import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from "@/components/ui/select"
function Tone() {
return (
<Select>
<SelectTrigger className="w-40">
<SelectValue placeholder="등급 선택" />
</SelectTrigger>
<SelectContent>
<SelectItem value="a">A 등급</SelectItem>
<SelectItem value="b">B 등급</SelectItem>
</SelectContent>
</Select>
)
}DropdownMenu
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem } from "@/components/ui/dropdown-menu"
import { Button } from "@/components/ui/button"
function Menu() {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline">메뉴</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem>편집</DropdownMenuItem>
<DropdownMenuItem>복제</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)
}Tabs
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs"
function Panel() {
return (
<Tabs defaultValue="info">
<TabsList>
<TabsTrigger value="info">정보</TabsTrigger>
<TabsTrigger value="log">기록</TabsTrigger>
</TabsList>
<TabsContent value="info">기본 정보…</TabsContent>
<TabsContent value="log">변경 기록…</TabsContent>
</Tabs>
)
}Sonner — toast
import { toast } from "sonner"
import { Button } from "@/components/ui/button"
function SaveButton() {
return (
<Button onClick={() => toast("저장됨")}>저장</Button>
)
}
// 앱 최상단(레이아웃)에 한 번만 <Toaster /> 를 둬야 알림이 보입니다.
// import { Toaster } from "@/components/ui/sonner"6. 모양 미리보기 (라이브)
shadcn 컴포넌트는 실제 파일이 없어 이 사이트에서 진짜로 실행할 수는 없어요. 아래는 Tailwind 클래스로 겉모습만 흉내 낸 "모양 미리보기"입니다(실제 동작 아님).
한눈에 — 컴포넌트 카탈로그
| 분류 | 컴포넌트 | 기반 프리미티브 |
|---|---|---|
| 폼 입력 | Button | react-slot |
Input | HTML | |
Textarea | HTML | |
Label | react-label | |
Checkbox | react-checkbox | |
RadioGroup | react-radio-group | |
Switch | react-switch | |
Select | react-select | |
Slider | react-slider | |
Toggle | react-toggle | |
Form | react-hook-form | |
| 오버레이 | Dialog | react-dialog |
AlertDialog | react-alert-dialog | |
Sheet | react-dialog | |
Popover | react-popover | |
HoverCard | react-hover-card | |
Tooltip | react-tooltip | |
DropdownMenu | react-dropdown-menu | |
ContextMenu | react-context-menu | |
Command | cmdk | |
| 표시 | Card | HTML |
Avatar | react-avatar | |
Badge | HTML | |
Separator | react-separator | |
ScrollArea | react-scroll-area | |
Tabs | react-tabs | |
Accordion | accordion | |
Collapsible | react-collapsible | |
Table | HTML | |
| 내비 · 피드백 | NavigationMenu | react-navigation-menu |
Breadcrumb | HTML | |
Toast | react-toast | |
Sonner | sonner | |
Skeleton | HTML |
이 컴포넌트들은 모두 프론트엔드 쪽 코드입니다(백엔드 아님). 복사된 파일은
study-frontend/src/components/ui/ 에 모여 있고,
코드에서는 @/components/ui/... 경로로 불러 씁니다.
실제로 위 표의 컴포넌트 대부분이 이 폴더에 .tsx 파일로 들어 있어요
(button, input, card, dialog, select, tabs, sonner 등).
다음 단계
- 컴포넌트를 조합하는 실전 패턴 → Shadcn UI · 자주 쓰는 패턴
- 바탕이 되는 스타일 방식 → Tailwind CSS
- Shadcn 개념 전체 → Shadcn UI