얻는 것
디자인 변경에 제약이 없다. 컴포넌트 코드를 읽고 이해할 수 있다. 안 쓰는 코드는 지워도 된다. 새 버전이 로컬 UI 코드를 자동 교체하지 않는다. 팀 컴포넌트로 자연스럽게 확장된다.
UI 컴포넌트를 통째로 제공하는 런타임 패키지를 설치하는 방식이 아니다. CLI는 실행하지만, 컴포넌트 소스는 내 레포에 들어온다.
컴포넌트 라이브러리Component Librarynode_modules 에 들어간다.프리미티브Primitive / Headless Component레지스트리Registrya11y / 접근성Accessibilitya 와 y 사이에 글자가 11개라 a11y라 줄여 쓴다.먼저 없으면 무슨 문제가 생기는지부터 보자. 전통적인 컴포넌트 라이브러리를 쓰면 이런 일이 생긴다.
import { Button } from 'some-ui-library'
<Button>저장</Button>디자이너가 “버튼 모서리를 좀 더 각지게, 그림자는 빼 주세요”라고 한다. 그런데 —
node_modules 안에 있다. 직접 고치면 재설치 때 사라지므로 공식 확장 API 안에서만 바꾸는 게 안전하다theme 설정으로 되는 범위까지만 가능하다!important로 덮어쓰기 시작한다pnpm dlx shadcn@latest add button✔ Created 1 file: - components/ui/button.tsx ← 내 레포에 생긴 파일복사돼 온 button.tsx 하나가 렌더하는 것이 이렇다 —
variant(성격)와 size(크기)라는 두 축이 독립적으로 조합된다.
variant="default"variant="secondary"variant="destructive"variant="outline"variant="ghost"variant="link"size="sm"size="default"size="lg"size="icon"disabled:focus-visible정당한 질문이다. 실제로 초기에는 복붙과 비슷했고, 지금은 네 가지가 다르다.
| 하는 일 | 없으면 | |
|---|---|---|
| 레지스트리 | 컴포넌트를 JSON으로 정의된 배포 단위로 관리 | 어느 버전을 복사했는지 알 수 없다 |
| 의존성 해결 | add dialog 하면 필요한 button도 함께 | 빠뜨린 파일을 찾아 헤맨다 |
| 토큰 주입 | 컴포넌트가 쓰는 CSS 변수를 globals.css에 자동 추가 | 색이 안 나오고 원인을 모른다 |
| 경로 조정 | 내 프로젝트 폴더 구조에 맞게 import 경로를 고쳐서 넣어 준다 | import 경로를 전부 손으로 고친다 |
그리고 --diff 명령이 있다. 내가 고친 파일과 최신 원본의 차이를 보여준다 —
복붙에는 이게 없다. (11장)
shadcn/ui 컴포넌트는 스타일만 들어 있는 게 아니다. 동작과 접근성은 아래층의 프리미티브가 담당한다.
소유권을 넘겨받는 건 노란 층뿐이다. 파란 층은 여전히 npm 패키지다 — 그게 다행이다.
모달 창 하나를 직접 만든다고 해보자. 눈에 보이는 것은 “어두운 배경 + 흰 상자”가 전부지만, 제대로 동작하려면 아래가 전부 필요하다.
role="dialog", aria-modal 이 붙어야 한다이걸 전부 직접 유지보수하고 싶은 사람은 없다. 그래서 이 부분만은 패키지로 남겨 둔다.
얻는 것
디자인 변경에 제약이 없다. 컴포넌트 코드를 읽고 이해할 수 있다. 안 쓰는 코드는 지워도 된다. 새 버전이 로컬 UI 코드를 자동 교체하지 않는다. 팀 컴포넌트로 자연스럽게 확장된다.
지는 책임
버그 수정이 자동으로 오지 않는다. 접근성 개선도 자동이 아니다. 팀원이 제각각 고치면 일관성이 무너진다. 어떤 파일을 고쳤는지 추적해야 한다. 새로 온 사람에게 “우리 규칙”을 알려줘야 한다.
오른쪽은 시간이 해결해 주지 않는다. 관리 구조를 의도적으로 만들어야 하고, 그 구조가 바로 이 덱이 말하는 테마다. 그래서 다음 장이 테마다.
반대로 디자인이 계속 진화하고 UI 코드를 관리할 팀이 있는 제품이라면 이 모델의 장점이 크다.
components/ui/)에 들어오고, 그때부터 내 코드다--diff