스타일 · Shadcn UI · 주요 컴포넌트

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/offreact-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
SonnerToast 대체 — 더 간단한 알림sonner 라이브러리
Skeleton로딩 중 자리표시(뼈대) UI순수 HTML + Tailwind
Toast vs Sonner

둘 다 "잠깐 뜨는 알림"입니다. 공식 문서는 이제 더 간단한 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 클래스로 겉모습만 흉내 낸 "모양 미리보기"입니다(실제 동작 아님).

한눈에 — 컴포넌트 카탈로그

분류컴포넌트기반 프리미티브
폼 입력Buttonreact-slot
InputHTML
TextareaHTML
Labelreact-label
Checkboxreact-checkbox
RadioGroupreact-radio-group
Switchreact-switch
Selectreact-select
Sliderreact-slider
Togglereact-toggle
Formreact-hook-form
오버레이Dialogreact-dialog
AlertDialogreact-alert-dialog
Sheetreact-dialog
Popoverreact-popover
HoverCardreact-hover-card
Tooltipreact-tooltip
DropdownMenureact-dropdown-menu
ContextMenureact-context-menu
Commandcmdk
표시CardHTML
Avatarreact-avatar
BadgeHTML
Separatorreact-separator
ScrollAreareact-scroll-area
Tabsreact-tabs
Accordionaccordion
Collapsiblereact-collapsible
TableHTML
내비 · 피드백NavigationMenureact-navigation-menu
BreadcrumbHTML
Toastreact-toast
Sonnersonner
SkeletonHTML
이 프로젝트와의 관계

이 컴포넌트들은 모두 프론트엔드 쪽 코드입니다(백엔드 아님). 복사된 파일은 study-frontend/src/components/ui/ 에 모여 있고, 코드에서는 @/components/ui/... 경로로 불러 씁니다. 실제로 위 표의 컴포넌트 대부분이 이 폴더에 .tsx 파일로 들어 있어요 (button, input, card, dialog, select, tabs, sonner 등).

다음 단계