이 글에서 정리하는 내용
Radix UI와 shadcn/ui를 경쟁 라이브러리처럼 오해해 선택 기준이 흐려지는 상황을 기준으로 원인을 좁히고, 실제 프로젝트에서 어떤 설정과 코드 구조를 확인해야 하는지 정리합니다. 단순 개념 소개가 아니라 오류가 난 순간 바로 확인할 순서와 선택 기준을 중심으로 설명합니다.
Radix UI와 shadcn/ui는 무엇이 다른가

Radix UI와 shadcn/ui는 같은 층위의 대체재로만 보면 헷갈립니다. Radix UI는 접근성 primitive를 제공하고, shadcn/ui는 Radix 같은 primitive와 Tailwind 스타일을 조합한 컴포넌트 코드를 프로젝트에 가져와 소유하게 하는 방식에 가깝습니다.
먼저 내가 원하는 것이 headless primitive인지, 바로 수정 가능한 완성형 컴포넌트 코드인지 구분합니다. Tailwind 기반으로 디자인을 빠르게 맞추고 싶다면 shadcn/ui가 편하고, 스타일 시스템을 직접 얹을 계획이라면 Radix primitive부터 보는 편이 단순합니다. 관련 흐름은 Tailwind CSS 실무 로드맵도 함께 참고할 수 있습니다.
라이브러리를 쓰는 방식과 코드를 소유하는 방식
Radix UI는 패키지로 설치해 primitive API를 조합하는 방식입니다. shadcn/ui는 CLI로 컴포넌트 파일을 내 프로젝트에 복사하고, 그 코드를 직접 수정하면서 가져가는 방식입니다. 그래서 업데이트와 커스터마이징 책임도 다르게 봐야 합니다.
shadcn/ui 컴포넌트 안에서 Radix primitive를 쓰는 경우가 많기 때문에 둘을 완전히 분리된 선택지로 볼 필요는 없습니다. “Radix를 쓸지 shadcn/ui를 쓸지”보다 “primitive부터 직접 만들지, 이미 조합된 컴포넌트를 가져와 고칠지”가 더 실제적인 질문입니다.
부분 예제 — 앞뒤 설명에 해당하는 코드만 적용하세요. 다른 예제와 합친 전체 프로젝트가 아닙니다.
// Radix UI는 primitive를 조합한다
// shadcn/ui는 프로젝트 코드로 복사해 수정한다
import { Dialog } from "@/components/ui/dialog";
위 import는 shadcn/ui 방식의 특징을 보여줍니다. 컴포넌트가 외부 패키지 안에 숨는 것이 아니라 @/components/ui/dialog 같은 프로젝트 경로에 들어오므로, 팀의 디자인 규칙에 맞춰 코드를 직접 고칠 수 있습니다.
이 방식은 자유도가 높은 대신 “업스트림 업데이트를 자동으로 받는다”는 기대와는 거리가 있습니다. 복사된 컴포넌트는 내 코드가 되므로, 수정 내역과 디자인 토큰을 팀 기준으로 관리해야 합니다.
접근성, 디자인 수정, 유지보수 기준 비교
접근성 primitive와 키보드 상호작용을 직접 조합하고 싶다면 Radix UI가 기준이 됩니다. 반대로 버튼, 다이얼로그, 폼 같은 UI를 빠르게 가져와 Tailwind 클래스와 디자인 토큰을 수정하려면 shadcn/ui가 작업 속도를 줄여줍니다.
상태 스타일을 많이 다룬다면 Tailwind의 data/aria variant와도 연결됩니다. Radix가 노출하는 상태 속성을 Tailwind 클래스로 스타일링하는 구조를 이해하면 shadcn/ui 컴포넌트도 훨씬 덜 낯설게 수정할 수 있습니다. Tailwind CSS 상태 variant 사용법도 함께 볼 만합니다.
Next.js와 Tailwind 프로젝트에서 선택 기준

Next.js와 Tailwind 프로젝트에서 빠르게 일관된 UI를 만들고 싶다면 shadcn/ui로 시작하는 흐름이 현실적입니다. 이미 Tailwind 설정과 path alias가 잡혀 있다면 컴포넌트를 추가하고 바로 프로젝트 스타일에 맞게 수정할 수 있습니다.
반대로 자체 디자인 시스템을 깊게 만들거나 Radix primitive 위에 완전히 다른 스타일 레이어를 얹을 계획이라면 Radix UI를 직접 조합하는 쪽이 맞을 수 있습니다. 어느 쪽이든 접근성 동작을 직접 깨뜨리지 않는지 확인해야 합니다.
처음 시작할 때 추천 흐름
처음 시작할 때는 완성된 화면이 필요한지, primitive 조합 경험이 필요한지부터 정합니다. 빠르게 제품 화면을 만들고 수정할 계획이면 shadcn/ui, 컴포넌트 내부 구조를 직접 설계할 계획이면 Radix UI를 먼저 봅니다.
프로젝트에서는 기본 원칙을 하나 정해 두는 편이 좋습니다. 예를 들어 일반적인 Button·Dialog·Form은 shadcn/ui를 기준으로 두고, 기존 컴포넌트로 해결하기 어려운 특수한 상호작용만 Radix primitive를 직접 조합하는 식입니다. 이렇게 하면 두 도구를 경쟁 관계로 볼 필요 없이 필요한 추상화 수준에 따라 선택할 수 있습니다.
컴포넌트를 고른 뒤에는 모양뿐 아니라 keyboard navigation, focus 처리, disabled 상태, 모바일 터치 동작까지 확인합니다. shadcn/ui 코드를 직접 수정하는 과정에서 Radix primitive가 제공하던 접근성 동작을 제거하지 않았는지도 함께 점검해야 합니다.
컴포넌트를 선택하기 전에 수정 책임을 정합니다
대화상자 하나가 필요한 상황을 가정하세요. 우리 팀이 직접 작성할 스타일, 포커스 동작을 확인할 사람, 업데이트 시 비교할 파일을 세 줄로 정리합니다.
풀이 기준과 확인 결과
Radix primitive는 동작을 조합하는 출발점이고 shadcn/ui는 프로젝트 안에서 수정하는 컴포넌트 코드가 출발점입니다. 도구 이름만으로 접근성 검수가 끝나지는 않습니다.
열기·닫기·Escape·포커스 복귀를 확인할 목록과 수정 파일의 위치를 말할 수 있으면 선택 근거가 구체적입니다. 본문 import 한 줄은 실행 가능한 전체 앱이 아닙니다.
함께 확인하면 좋은 기준
이 글과 관련해 실제 작업에서 같이 확인하면 좋은 기준입니다.
- shadcn/ui Docs: 적용 전 현재 문서의 권장 API, 설정 옵션, 제한 사항이 글의 설명과 맞는지 확인합니다.
- Radix UI Primitives Docs: 적용 전 현재 문서의 권장 API, 설정 옵션, 제한 사항이 글의 설명과 맞는지 확인합니다.
- 비슷한 오류를 구분할 때는 발생 위치, 실행 환경, 재현 조건을 먼저 분리해 확인합니다.
- 프로젝트에 적용할 때는 기존 코드 구조, 의존성 버전, 배포 환경에서 같은 기준이 유지되는지 확인합니다.
연결 학습: 컴포넌트 선택을 입력 폼에 적용하기
목표·선행 지식: Radix의 상호작용 기반과 shadcn/ui의 프로젝트 소스 관리 방식을 비교합니다.
Input·Textarea의 값은 React state로 관리하고 label을 연결합니다. Button의 시각적 variant와 submit 같은 HTML 동작은 별개입니다. cn은 클래스 결합과 충돌 정리를 돕지만 존재하지 않는 Tailwind CSS를 생성하지 않습니다.
직접 확인할 과제
버튼 모양만 변경한 뒤 Enter 제출이 여전히 동작하는지 확인하세요. Dialog는 열기·닫기·포커스 복귀, Popover는 트리거 이름, Carousel은 이전·다음 버튼의 경계 상태까지 확인합니다.
공통 실습 ZIP · 다음 학습 · 라이브러리 선택 가이드
공통 ZIP은 버전을 고정한 학습 예제입니다. UI 파일은 Radix·Sonner·Embla 기반 축약 구현이며 shadcn CLI 생성물과 동일하지 않습니다. 적용 범위와 실행 방법은 ZIP의 README를 확인하세요.
이 글이 도움이 되었나요?
Tailwind CSS 학습 순서
필수 15개 · 전체 22개
읽음 기록 관리
전체 과정 목차 (22개)
- 필수 길잡이 · Tailwind CSS 실전 로드맵: 기본·반응형·상태·동적 클래스 학습 순서
- 필수 학습 · Tailwind CSS 기본 클래스 사용법: text font bg spacing 익히기
- 필수 학습 · Tailwind border flex 사용법: 레이아웃 기본 클래스 기준
- 필수 학습 · Tailwind CSS Preflight 기준: 기본 스타일 초기화가 생기는 이유
- 필수 학습 · Tailwind CSS Grid 실무 레이아웃 정리: 카드 목록부터 대시보드까지
- 필수 학습 · Tailwind CSS 반응형 클래스 사용법: sm md lg 기준 잡기
- 필수 학습 · Tailwind CSS 상태 variant 사용법: hover focus aria data 기준 잡기
- 필수 학습 · Tailwind CSS group peer has 차이: 상태 기준으로 고르는 방법
- 필수 학습 · Tailwind CSS dark 사용법: 다크 모드 구현 기준 잡기
- 필수 학습 · Tailwind CSS arbitrary value 차이: 대괄호 문법 사용 기준 잡기
- 선택 참고 · Tailwind CSS 임의 값 공백 처리: 대괄호 문법이 깨질 때 해결하기
- 필수 학습 · Tailwind CSS @theme 사용법: 변수와 디자인 토큰 구분하기
- 필수 학습 · Tailwind Container Query 사용법: 부모 너비 기준 반응형 처리
- 필수 학습 · React Tailwind className 정리: 조건부·variant·가독성 기준
- 필수 학습 · Tailwind CSS 동적 클래스 해결: 감지 원리와 @source 사용법
- 필수 학습 · Tailwind CSS @apply 사용 기준: @utility와 custom variant 구분하기
- 선택 참고 · Tailwind CSS transition, animation, motion-reduce 사용 기준 정리
- 선택 참고 · Tailwind CSS v4.1 유틸리티 정리: text-shadow와 mask 사용하기
- 선택 참고 · Radix UI와 shadcn/ui 차이: 컴포넌트를 고를 때 헷갈리는 기준 정리 현재 글
- 선택 참고 · shadcn/ui No import alias found 오류 해결: tsconfig 설정
- 선택 참고 · Tailwind CSS flex 레이아웃 깨질 때 확인할 것
- 선택 참고 · Tailwind CSS 클래스 적용 안 됨 해결 순서
새 글 받아보기
RSS 리더에서 BlogFlow의 새 글을 확인할 수 있습니다.