[G1-Sync] Manual knowledge update
This commit is contained in:
@@ -1,93 +1,292 @@
|
||||
---
|
||||
id: wiki-2026-0508-shadcn-ui
|
||||
title: shadcn ui
|
||||
title: shadcn/ui
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [shadcn, shadcn-ui, shadcn/ui, ui.shadcn.com]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [uncategorized]
|
||||
confidence_score: 0.95
|
||||
verification_status: applied
|
||||
tags: [react, ui, components, tailwind, radix, design-system]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: TypeScript
|
||||
framework: React 19/Next.js 15/Tailwind 4/Radix UI
|
||||
---
|
||||
|
||||
# shadcn/ui
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
shadcn/ui는 [[Tailwind CSS|Tailwind CSS]]를 위해 설계된 React UI 컴포넌트 라이브러리 및 프리미티브 모음입니다 [1, 2]. 주로 Radix와 같은 Headless UI와 함께 사용되며, 복잡한 상호작용과 상태 관리를 지원하는 정교하고 재사용 가능한 컴포넌트를 구축하는 데 사용됩니다 [3, 4]. 특히 [[Next.js App Router|Next.js App Router]]를 사용하는 중소규모의 애플리케이션에서 Tailwind CSS와 결합하여 사용할 때 가장 권장되는 접근 방식 중 하나입니다 [2].
|
||||
## 매 한 줄
|
||||
> **"매 install package 가 아니라 매 copy-paste component collection — 매 source code 매 own, 매 customize 자유"**. shadcn (Shaad Heuvel) 매 2023 출시, 매 React + Tailwind + Radix UI 위에 매 well-designed accessible primitive 를 매 CLI 로 가져다 쓰는 anti-library pattern. 2026 현재 매 React app 의 default UI starting kit — Vercel templates, AI SDK examples, Next.js docs 매 default.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
- **Tailwind CSS 기반 생태계:** shadcn/ui는 Tailwind CSS 환경에 완벽하게 맞춰 설계되었으며, 주로 [[Radix UI|Radix UI]] 및 Headless UI와 결합하여 사용됩니다 [1, 3]. 이는 [[CSS-in-JS|CSS-in-JS]]의 런타임 오버헤드를 피하고 유틸리티 클래스 기반의 빠른 렌더링 성능을 활용하는 현대적인 스타일링 접근 방식과 맞닿아 있습니다 [2, 5].
|
||||
- **컴포넌트 프리미티브 제공:** 새로운 프로젝트(특히 [[Next.js|Next.js]] App Router 기반의 중소규모 앱)를 구축할 때, 처음부터 UI를 작성하는 대신 프리미티브(Component primitives) 역할을 하여 빠른 개발을 돕습니다 [2].
|
||||
- **고급 컴포넌트 패턴 지원:** 유연하고 확장 가능한 API를 설계하기 위해 컴파운드 컴포넌트(Compound component) 아키텍처 패턴을 적극적으로 활용합니다 [4]. 이를 통해 하나의 거대한 컴포넌트에 수많은 prop을 전달하는 대신, 논리적으로 협력하는 여러 하위 컴포넌트로 책임을 분산시켜 복잡한 요구사항을 해결합니다 [3, 6].
|
||||
- **확장 가능한 스타일링 및 성능 최적화:** 변형(variant) 시스템, 반응형 디자인, 테마 통합과 같은 고급 스타일링 기법을 마스터할 수 있는 구조를 갖추고 있습니다 [4]. 효율적인 렌더링과 상태 관리를 위한 성능 최적화 기술도 내장하고 있습니다 [4].
|
||||
- **타입 안정성 보장:** TypeScript를 기반으로 구축되어 있어, 오류를 방지하고 완벽한 타입 안정성을 제공하는 컴포넌트 개발 및 API 설계가 가능합니다 [4].
|
||||
## 매 핵심
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Related Topics:** [[Tailwind CSS|Tailwind CSS]], Compound Components, [[Headless UI|Headless UI]], Radix
|
||||
- **Projects/Contexts:** [[Next.js App Router 프로젝트|Next.js App Router 프로젝트]], 재사용 가능한 React 컴포넌트 라이브러리 설계
|
||||
- **Contradictions/Notes:** 소스 상에서 shadcn/ui는 전통적인 의미의 무거운 UI 프레임워크라기보다는, Tailwind CSS와 결합하여 개발자에게 강력한 통제권과 유연성을 제공하는 프리미티브 모음으로 묘사되고 있습니다 [1, 2].
|
||||
### 매 differentiator
|
||||
- **Not a dependency**: 매 `npm install shadcn/ui` 가 아님. 매 `npx shadcn add button` → component code 매 your repo 에 copy.
|
||||
- **Owned source**: 매 매 component file 매 직접 modify. 매 lock-in 없음.
|
||||
- **Built on Radix UI**: accessibility primitives (focus management, ARIA, keyboard) 매 무료.
|
||||
- **Tailwind**: utility-first styling, theme via CSS variables.
|
||||
- **Composable**: 매 small primitive (Button, Input, Dialog) 매 large block 으로 조합.
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-26*
|
||||
### 매 stack
|
||||
- **Foundation**: Radix UI Primitives (unstyled accessible components).
|
||||
- **Styling**: Tailwind CSS v4 (2024+ JIT engine).
|
||||
- **Variants**: `class-variance-authority` (cva) — type-safe variant API.
|
||||
- **Class merge**: `tailwind-merge` + `clsx` (`cn()` helper).
|
||||
- **Forms**: `react-hook-form` + `zod` (resolver).
|
||||
- **Charts**: Recharts wrapper (shadcn/charts).
|
||||
- **Icons**: lucide-react.
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
|
||||
- **과거 데이터와의 충돌:** 없음
|
||||
- **정책 변화:** 없음
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
### 매 CLI workflow
|
||||
```bash
|
||||
npx shadcn@latest init # one-time setup, creates components.json
|
||||
npx shadcn@latest add button input dialog
|
||||
npx shadcn@latest add https://ui.shadcn.com/r/styles/new-york/login-01.json
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 매 응용
|
||||
1. SaaS dashboard / admin panel.
|
||||
2. AI chat UI (shadcn/ui + Vercel AI SDK).
|
||||
3. Marketing site sections.
|
||||
4. Internal tools (Retool 대체).
|
||||
5. Design system foundation (매 fork 후 brand 적용).
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
## 💻 패턴
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 1. Initial setup (Next.js 15)
|
||||
```bash
|
||||
pnpm create next-app@latest my-app --ts --tailwind --app
|
||||
cd my-app
|
||||
pnpm dlx shadcn@latest init
|
||||
# choose: New York style, Slate base, CSS variables
|
||||
pnpm dlx shadcn@latest add button card input form dialog dropdown-menu
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### 2. cn() utility (필수 helper)
|
||||
```typescript
|
||||
// lib/utils.ts
|
||||
import { clsx, type ClassValue } from "clsx";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 3. Button with cva variants
|
||||
```tsx
|
||||
import * as React from "react";
|
||||
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 ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
||||
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
||||
outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
||||
ghost: "hover:bg-accent hover:text-accent-foreground",
|
||||
},
|
||||
size: {
|
||||
default: "h-10 px-4 py-2",
|
||||
sm: "h-9 rounded-md px-3",
|
||||
lg: "h-11 rounded-md px-8",
|
||||
icon: "h-10 w-10",
|
||||
},
|
||||
},
|
||||
defaultVariants: { variant: "default", size: "default" },
|
||||
}
|
||||
);
|
||||
|
||||
export interface ButtonProps
|
||||
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
||||
VariantProps<typeof buttonVariants> {
|
||||
asChild?: boolean;
|
||||
}
|
||||
|
||||
export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
({ className, variant, size, asChild = false, ...props }, ref) => {
|
||||
const Comp = asChild ? Slot : "button";
|
||||
return <Comp className={cn(buttonVariants({ variant, size, className }))} ref={ref} {...props} />;
|
||||
}
|
||||
);
|
||||
Button.displayName = "Button";
|
||||
```
|
||||
|
||||
### 4. Form with react-hook-form + zod
|
||||
```tsx
|
||||
"use client";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { z } from "zod";
|
||||
import { Form, FormField, FormItem, FormLabel, FormControl, FormMessage } from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
const schema = z.object({
|
||||
email: z.string().email(),
|
||||
password: z.string().min(8),
|
||||
});
|
||||
|
||||
export function LoginForm() {
|
||||
const form = useForm<z.infer<typeof schema>>({
|
||||
resolver: zodResolver(schema),
|
||||
defaultValues: { email: "", password: "" },
|
||||
});
|
||||
|
||||
function onSubmit(values: z.infer<typeof schema>) {
|
||||
// server action
|
||||
}
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
|
||||
<FormField control={form.control} name="email" render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Email</FormLabel>
|
||||
<FormControl><Input type="email" {...field} /></FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)} />
|
||||
<FormField control={form.control} name="password" render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Password</FormLabel>
|
||||
<FormControl><Input type="password" {...field} /></FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)} />
|
||||
<Button type="submit" className="w-full">Sign in</Button>
|
||||
</form>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### 5. Theming (CSS variables)
|
||||
```css
|
||||
/* app/globals.css */
|
||||
@import "tailwindcss";
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 222.2 84% 4.9%;
|
||||
--primary: 221.2 83.2% 53.3%;
|
||||
--primary-foreground: 210 40% 98%;
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
.dark {
|
||||
--background: 222.2 84% 4.9%;
|
||||
--foreground: 210 40% 98%;
|
||||
--primary: 217.2 91.2% 59.8%;
|
||||
--primary-foreground: 222.2 47.4% 11.2%;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 6. Data table (TanStack Table integration)
|
||||
```tsx
|
||||
import { ColumnDef, flexRender, getCoreRowModel, useReactTable } from "@tanstack/react-table";
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
|
||||
|
||||
export function DataTable<T, V>({ columns, data }: { columns: ColumnDef<T, V>[]; data: T[] }) {
|
||||
const table = useReactTable({ data, columns, getCoreRowModel: getCoreRowModel() });
|
||||
return (
|
||||
<Table>
|
||||
<TableHeader>
|
||||
{table.getHeaderGroups().map((hg) => (
|
||||
<TableRow key={hg.id}>
|
||||
{hg.headers.map((h) => (
|
||||
<TableHead key={h.id}>{flexRender(h.column.columnDef.header, h.getContext())}</TableHead>
|
||||
))}
|
||||
</TableRow>
|
||||
))}
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{table.getRowModel().rows.map((row) => (
|
||||
<TableRow key={row.id}>
|
||||
{row.getVisibleCells().map((c) => (
|
||||
<TableCell key={c.id}>{flexRender(c.column.columnDef.cell, c.getContext())}</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### 7. AI chat UI (Vercel AI SDK + shadcn)
|
||||
```tsx
|
||||
"use client";
|
||||
import { useChat } from "@ai-sdk/react";
|
||||
import { Card } from "@/components/ui/card";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
export function Chat() {
|
||||
const { messages, input, handleInputChange, handleSubmit } = useChat();
|
||||
return (
|
||||
<div className="flex flex-col h-[600px] gap-2">
|
||||
<div className="flex-1 overflow-y-auto space-y-2 p-4">
|
||||
{messages.map((m) => (
|
||||
<Card key={m.id} className={cn("p-3", m.role === "user" && "bg-primary/10")}>
|
||||
<strong className="text-xs uppercase">{m.role}</strong>
|
||||
<p className="whitespace-pre-wrap">{m.content}</p>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
<form onSubmit={handleSubmit} className="flex gap-2 p-2">
|
||||
<Input value={input} onChange={handleInputChange} placeholder="Say something..." />
|
||||
<Button type="submit">Send</Button>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| 빠른 SaaS prototype | shadcn/ui + Next.js + Vercel — 매 default 선택 |
|
||||
| 강한 brand identity | shadcn/ui fork → CSS variables 로 brand 적용 |
|
||||
| 매 component lock-in 싫음 | shadcn/ui (own source) |
|
||||
| 매 dependency 관리 single 파일 선호 | Material UI / Mantine (전통 lib) |
|
||||
| 매 enterprise tabular admin | shadcn/ui + TanStack Table + Recharts |
|
||||
| 매 native mobile (RN) | NativeBase / Tamagui / shadcn-react-native (community) |
|
||||
|
||||
**기본값**: Next.js 15 + shadcn/ui (New York style) + Tailwind 4 + lucide-react + react-hook-form + zod.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[React]] · [[Component Libraries]] · [[Design Systems]]
|
||||
- 변형: [[Material UI]] · [[Mantine]] · [[Chakra UI]] · [[Radix UI]]
|
||||
- 응용: [[Next.js]] · [[Vercel AI SDK]] · [[TanStack Table]]
|
||||
- Adjacent: [[Tailwind CSS]] · [[class-variance-authority]] · [[Lucide Icons]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: 매 modern React app 매 빠르게 launch — 매 LLM (Claude/GPT) 매 shadcn 패턴 매 well-trained, 매 generation quality 매 높음.
|
||||
**언제 X**: 매 design-from-scratch creative work — 매 too opinionated. 매 매 non-React framework (Vue/Svelte) — 매 community port 있지만 매 first-class 아님.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **shadcn 을 npm package 처럼 취급**: 매 update CLI 매 `npx shadcn diff` 로 검토 후 매 manually merge.
|
||||
- **cn() 무시**: 매 className concat 매 직접 — 매 conflict 매 발생.
|
||||
- **Tailwind v3 와 mix**: 매 v4 와 v3 매 incompatible API. 매 lock 명시.
|
||||
- **Radix unstyle 무시 직접 div**: 매 accessibility 손실.
|
||||
- **모든 Button 을 custom variant 로**: 매 base variant 4-5개 유지, 매 outlier 만 inline className.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (ui.shadcn.com docs, Next.js learn, Vercel templates 2025-2026).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — full setup + cva + form + AI chat patterns (2026 stack) |
|
||||
|
||||
Reference in New Issue
Block a user