디자인이 어려운 진짜 이유는 그리는 능력이 아니라 매 화면마다 다시 정하는 결정입니다. shadcn/create는 그 결정을 10개 항목으로 줄이고, 결과를 짧은 프리셋 코드에 담아줍니다.
프리셋의 CSS 변수를 전부 세어봤습니다. 색상 변수 62개 중 채도가 있는 진짜 “색”은 3개, 나머지 59개는 회색이었습니다.
무작위 셔플로 정반대 조합을 뽑아도 화면은 안 무너졌습니다. 일관성은 취향이 아니라 시스템의 문제라는 게 이 실측의 결론입니다.
커스텀 테마를 만들 때 저는 강조색을 하나로, 모서리 반경을 하나로 못박았습니다. 디자인 감각이 있어서가 아니라, 고를 수 있는 걸 줄여야 화면이 안 무너진다는 걸 알았기 때문입니다. 그런데 그 “줄이는 일”을 화면에서 클릭으로 해주는 도구가 나왔습니다. shadcn/ui의 /create입니다. 어디까지 되는지 직접 확인했습니다.
디자인이 어려운 진짜 이유
버튼 하나를 만들어도 정할 게 많습니다. 배경색, 글자색, 모서리, 그림자, 글꼴, 크기. 문제는 다음 화면에서 이걸 또 정한다는 겁니다. 그때마다 조금씩 다르게 정하면, 각 화면은 멀쩡한데 전체가 어수선해집니다.
그러니까 못 그려서 못생겨지는 게 아닙니다. 같은 질문에 매번 다른 답을 해서 못생겨집니다. 해결책은 감각을 기르는 게 아니라 답을 한 번만 정하고 다시 안 묻는 것 — 즉 시스템입니다.
shadcn/create가 하는 일
ui.shadcn.com/create를 열면 왼쪽에 설정 패널, 오른쪽에 실제 UI 컴포넌트(대시보드, 폼, 차트, 달력)가 가득한 미리보기가 뜹니다. 왼쪽에서 하나 바꾸면 오른쪽 전체가 즉시 바뀝니다.

고를 수 있는 항목을 세어봤더니 10개가 전부입니다.
| 항목 | 정하는 것 |
|---|---|
| Style | 전체 스타일 (컴포넌트 생김새의 큰 틀) |
| Base Color | 회색 계열 (Neutral, Stone, Zinc…) |
| Theme | 강조색 |
| Chart Color | 차트 색 계열 |
| Heading / Font | 제목·본문 글꼴 |
| Icon Library | 아이콘 세트 (Lucide, Phosphor…) |
| Radius | 모서리 반경 |
| Menu / Menu Accent | 메뉴 배경·강조 방식 |
버튼 하나에 무한한 선택지가 있던 세계가 결정 10개로 줄어듭니다. 그리고 이 10개를 정하면 주소창에 짧은 코드가 붙습니다.
https://ui.shadcn.com/create?preset=bbVJxYW
이 코드가 설정 전체입니다. CLI로 풀어볼 수도 있습니다.
$ npx shadcn@latest preset decode bbVJxYW
style maia
baseColor neutral
theme neutral
chartColor neutral
iconLibrary lucide
font inter
fontHeading inherit
radius default
menuAccent subtle
menuColor default
팀원에게 디자인 시스템을 넘기는 일이 7글자를 보내는 일이 된 셈입니다.
프리셋 안에 진짜 “색”은 몇 개나 될까
위 프리셋의 테마 파일(CSS 변수 2,254자)을 받아 파싱했습니다. 결과가 이 글에서 제일 재미있는 숫자입니다.
| 측정 | 값 |
|---|---|
| 변수 선언 (라이트+다크) | 63개 |
| 그중 색상(oklch) 변수 | 62개 |
| 채도 > 0, 진짜 “색” | 3개 |
| 무채색 (회색) | 59개 |
진짜 색 3개의 정체도 확인했습니다. 삭제 버튼용 빨강이 라이트·다크 하나씩, 그리고 다크 모드 사이드바 주 색상용 파랑 하나. 끝입니다. 배경, 카드, 테두리, 입력창, 차트 다섯 단계까지 전부 회색의 농도 차이로만 굴러갑니다.
이게 제가 타입 스케일 글에서 간격을 4px 배수로 못박았던 것과 같은 원리입니다. 잘 만든 화면은 색이 많아서가 아니라 색이 적고 역할이 분명해서 정돈돼 보입니다.
무작위로 섞어도 안 무너질까 — 셔플 실험
여기까지면 “회색으로 가라”는 흔한 결론입니다. 그래서 반대 실험을 했습니다. 패널의 Shuffle 버튼은 10개 항목을 무작위로 다시 뽑습니다. 한 번 눌렀더니 이렇게 나왔습니다.
| 항목 | 원래 (bbVJxYW) | 셔플 (b3Zheoix4U) |
|---|---|---|
| Style | Maia | Sera |
| Theme | Neutral | Emerald (초록) |
| Chart Color | Neutral | Cyan (청록) |
| Heading / Font | Inter / Inter | Geist / Oxanium |
| Icon Library | Lucide | Phosphor Icons |
| Radius | Default | None (직각) |

초록 버튼, 청록 차트, 직각 모서리, 대문자 라벨. 인상은 완전히 다른데 — 안 못생겼습니다. 무작위 조합인데도 화면 전체가 여전히 한 벌로 보입니다.
이게 이 실측의 결론을 바꿨습니다. 회색이 정답이어서 정돈돼 보였던 게 아닙니다. 적어도 이 도구가 뽑아주는 조합 안에서는, 화면 전체가 같은 답을 공유하는 한 정돈돼 보입니다. 못생겨지는 순간은 딱 하나, 정해놓은 답을 어기고 한 군데서만 다른 색·다른 반경을 쓸 때입니다.
일관성은 취향의 문제가 아니라 시스템의 문제다.
결과물 받는 법 — React가 없어도 됩니다
우상단 Get Code를 누르면 세 가지 방식이 나옵니다.
① 새 프로젝트. 템플릿(Next.js·Vite·TanStack Start·Laravel·React Router·Astro)을 고르면 명령 한 줄을 줍니다.
npx shadcn@latest init --preset bbVJxYW --template next
컴포넌트 베이스도 고를 수 있습니다. 2026년 7월부터 기본이 Radix UI에서 Base UI로 바뀌었고, React Aria와 Radix UI도 선택지로 남아 있습니다.
② 기존 프로젝트. 이미 있는 프로젝트에 프리셋만 얹습니다.
③ Theme. 여기가 반전입니다. React도 CLI도 아닌 순수 CSS 변수를 줍니다.
:root {
--background: oklch(1 0 0);
--foreground: oklch(0.145 0 0);
--primary: oklch(0.205 0 0);
--border: oklch(0.922 0 0);
--radius: 0.625rem;
/* …총 63개, 다크 모드 포함 */
}
그냥 CSS라서 워드프레스든 순수 HTML이든 어디든 붙습니다. 이 블로그도 React 없이 워드프레스 커스텀 테마로 돌아가는데, 이 변수들을 그대로 가져다 쓸 수 있습니다. shadcn을 “React 라이브러리”로만 알고 있었다면, 결정만 빌려오는 용도로도 쓸 수 있다는 뜻입니다.
다만 정직하게 적어두면 — 변수는 선언일 뿐 스스로 아무것도 안 바꿉니다. background: var(--background)처럼 내 CSS가 변수를 참조하도록 연결하는 일은 직접 해야 합니다. 도구가 대신 정해주는 건 “값”이지 “적용”이 아닙니다.
정리
- 디자인이 어려운 건 감각이 아니라 매번 다시 하는 결정 때문이다
- shadcn/create는 결정을 10개 항목으로 줄이고 짧은 프리셋 코드로 압축한다
- 잘 만든 기본 테마를 열어보면 색상 변수 62개 중 진짜 색은 3개다
- 무작위 셔플도 안 무너진다 — 일관성은 시스템의 문제고, 못생겨지는 건 정한 걸 어길 때다
- Get Code의 Theme 탭은 순수 CSS 변수라 React 없이 워드프레스에도 붙는다
- 단, 변수 선언과 적용은 별개 — 연결은 직접 해야 한다
이 블로그를 만들며 정한 규칙 — 강조색 하나·반경 하나, 간격은 4px 배수 — 도 결국 같은 이야기였습니다. 그때는 디자인 시스템을 손으로 하나씩 정했는데, 이제는 화면에서 10번 클릭하면 됩니다.