ADR-0029: UI Library: shadcn/ui¶
Umbra 의 대시보드 UI 컴포넌트는 shadcn/ui 로 구성한다. Tailwind CSS 기반이며 컴포넌트 코드는 npm 패키지가 아닌 프로젝트에 직접 복사되어 커스터마이징 자유도가 높다.
Status¶
Accepted
- Decided at — 2026-04-13
- Decided by — Pablo
Context¶
React SPA (ADR-0008) 를 채택한 후 UI 컴포넌트 라이브러리를 선택해야 한다. Umbra 의 Dashboard 는 다음 UI 요구를 가진다.
- 폼 (구독 신청, 설정 변경)
- 테이블 (구독 내역, 복구 이력, 멤버 목록)
- 모달/다이얼로그 (복구 확인, 결제 등록)
- 네비게이션 (사이드바, 탭)
- 데이터 시각화 (복구 진행 상황, 차트)
후보: shadcn/ui, Material UI, Ant Design, Chakra UI, Radix + 자체 스타일링, Park UI.
Decision¶
shadcn/ui 를 채택한다.
- Base — Radix UI primitives (접근성 + 동작 로직)
- Styling — Tailwind CSS
- Distribution — 컴포넌트 코드를 프로젝트에 직접 복사 (
apps/web/src/components/ui/) - Icon — Lucide React
Installation pattern¶
복사된 코드는 프로젝트 일부로 취급되며 자유롭게 수정 가능.
선택 근거:
- 디자인 자유도 — 컴포넌트 코드가 프로젝트에 있어 직접 수정 가능. 라이브러리 업데이트에 종속되지 않음
- 접근성 — Radix UI primitives 기반이라 키보드 네비게이션, ARIA 속성 기본 제공
- Tailwind 통합 — Luxtra 팀의 Tailwind 중심 스타일링 컨벤션과 일치
- 디자인 토큰 적용성 — CSS variables (
--primary,--background등) 기반으로 Luxtra 디자인 토큰 적용 용이 - shadcn-react 생태계 성숙 — 작성 시점 기준 React 대시보드에서 사실상 표준 위치
Consequences¶
Positive¶
- 디자인 토큰(Luxtra 브랜드 색상, 타이포) 적용이 CSS variable 교체만으로 가능
- 컴포넌트 코드 수정이 자유로워 디자인 요구 변화에 유연
- npm 패키지 의존성 최소화 (Radix + Tailwind 만 의존)
- 번들 크기 ↓ (사용하는 컴포넌트만 포함)
- 접근성 기본값 보장
Negative¶
- 컴포넌트 코드가 프로젝트에 복사되어 업데이트 추적 수동
- Material UI 대비 "한 번에 많은 컴포넌트" 가 제공되지 않아 초기 수동 복사 작업
- 커스터마이징 자유도가 오히려 팀 간 일관성 위협 (컨벤션 필요)
Neutral¶
- Luxtra 의 다른 프로젝트(luxtra.dev)도 shadcn/ui 기반이라 팀 스택 일관성
- Tailwind v4 가 stable 이후에도 shadcn 이 지원 확인됨
Design system integration¶
Luxtra 의 브랜드 디자인 토큰(LUXTRA.md Brand Kit)을 shadcn 의 CSS variables 에 매핑한다.
/* apps/web/src/styles/globals.css */
@layer base {
:root {
--primary: 270 91% 65%; /* Luxtra Purple #A855F7 */
--background: 240 20% 5%; /* Luxtra Dark #08080F */
--card: 240 16% 8%; /* Luxtra Card #0F0E1A */
--border: 270 91% 65% / 0.12; /* Luxtra Border */
/* ... */
}
}
Umbra 는 Luxtra 브랜드 기반이되 umbra.ink 의 자체 아이덴티티 도 반영한다. 보조 색상(어둠/그림자 테마) 을 umbra 전용 variable 로 추가.
Component selection strategy¶
Include (바로 추가)¶
SaaS 대시보드 기본 구성:
- Button, Input, Textarea, Select, Checkbox, Switch
- Dialog, Sheet, Popover, Tooltip
- Table, Pagination, Badge, Avatar
- Tabs, Accordion, Card
- Form (React Hook Form + Zod 통합)
- Toast (Sonner)
- Alert, Alert Dialog
Defer (필요 시 추가)¶
- Date Picker — 결제 이력 조회 시 필요
- Command Palette — Phase 2 UX 개선
- Combobox — 대형 길드 멤버 선택 시
Not include¶
- Navigation Menu (mega menu) — 대시보드 규모에 과함
- Carousel — Umbra 의 UI 에 부적합
- Calendar — Umbra 에 일정 기능 없음
Alternatives considered¶
Alternative 1: Material UI (MUI)¶
Pros
- 컴포넌트 매우 풍부
- 성숙한 생태계
Cons
- 디자인 커스터마이징이 theme config 기반으로 복잡
- Tailwind 와 충돌 (CSS-in-JS 기반)
- 번들 크기 큼
Why rejected — Tailwind 중심 스택(Luxtra 팀 컨벤션)과 맞지 않음.
Alternative 2: Ant Design¶
Pros
- 엔터프라이즈 대시보드에 강함
Cons
- 디자인이 "Ant Design 스타일" 로 각인되어 브랜드화 어려움
- Tailwind 와 충돌
- 커스터마이징 비용 ↑
Why rejected — 브랜드 아이덴티티 표현에 부적합.
Alternative 3: Chakra UI¶
Pros
- 접근성 우수
- API 친화적
Cons
- CSS-in-JS (emotion) 기반 → Tailwind 와 충돌
- Chakra v3 의 큰 변경으로 안정성 우려
- Luxtra 스택 방향성과 차이
Why rejected — Tailwind 우선 원칙과 맞지 않음.
Alternative 4: Radix UI primitives + 자체 스타일링¶
Pros
- 완전 제어
Cons
- 기본 스타일링을 전부 자체 구현
- shadcn/ui 가 결국 이것을 제공하므로 중복 작업
Why rejected — shadcn/ui 가 하위 호환. Radix 는 이미 shadcn 에 포함.
Alternative 5: Park UI¶
Pros
- shadcn 스타일 + 여러 프레임워크 지원 (React, Vue, Solid)
Cons
- shadcn 대비 성숙도 낮음
- Umbra 는 React 단일 → 멀티프레임워크 이점 없음
Why rejected — shadcn 이 더 성숙한 선택.
Compliance¶
- UI 컴포넌트는
apps/web/src/components/ui/에만 위치 (shadcn 추가 컴포넌트) - Feature 컴포넌트는
apps/web/src/features/{feature}/에 위치 components/ui/는 shadcn 컴포넌트 전용 (커스텀 팽창 금지)- 팀 공통 커스터마이징은 CSS variables 변경으로 일원화
- 아이콘은
lucide-react만 사용 (Radix icons 등 혼용 금지)
Revisit triggers¶
- shadcn/ui 가 유지보수 중단되면 fork 또는 이전 검토
- Tailwind 버전 호환성 이슈가 반복되면 stack 재평가
- 팀이 커져서 "컴포넌트 라이브러리 커스터마이징" 일관성이 문제가 되면 내부 컴포넌트 라이브러리 정리 필요