콘텐츠로 이동

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

# 컴포넌트 추가 시
bunx shadcn@latest add button
# → apps/web/src/components/ui/button.tsx 에 코드가 복사됨

복사된 코드는 프로젝트 일부로 취급되며 자유롭게 수정 가능.

선택 근거:

  • 디자인 자유도 — 컴포넌트 코드가 프로젝트에 있어 직접 수정 가능. 라이브러리 업데이트에 종속되지 않음
  • 접근성 — 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 재평가
  • 팀이 커져서 "컴포넌트 라이브러리 커스터마이징" 일관성이 문제가 되면 내부 컴포넌트 라이브러리 정리 필요

References

  • ADR-0008 — React + Vite 스택
  • ADR-0028 — TanStack 라우팅 (shadcn Form 과 결합)