Tailwind와 shadcn/ui 기술 설명해줘
Tailwind CSS와 shadcn/ui는 현대 웹 개발에서 매우 인기 있는 도구들이며, 서로 완벽하게 조화되는 관계입니다. 따로 설명해드릴게요.
1. Tailwind CSS: 유틸리티 퍼스트(Utility-First) CSS 프레임워크
간단히 말하면: CSS를 직접 작성하지 않고, 미리 정의된 클래스 이름들을 HTML에 조합하여 디자인하는 CSS 프레임워크입니다.
핵심 개념:
-
유틸리티 퍼스트: flex
, pt-4
, text-center
, bg-blue-500
같은 작은 단위의 클래스들을 Lego 블록처럼 조합해 전체 디자인을 완성합니다.
-
직관적: 클래스 이름이 스타일을 그대로 설명합니다. (예: text-red-600
은 빨간색 텍스트, p-4
는 padding 4단위)
-
커스터마이징 용이: tailwind.config.js
파일을 통해 디자인 시스템(색상, 폰트, 간격 등)을 자신의 프로젝트에 맞게 쉽게 재정의할 수 있습니다.
-
번들 크기 최적화: PurgeCSS(현재는 Content 옵션) 기능을 통해 실제로 사용하는 클래스만 최종 CSS 파일에 포함시켜 용량을 최소화합니다.
기존 CSS 프레임워크(Bootstrap, Bulma)와의 차이점:
-
Bootstrap: 미리 만들어진 컴포넌트(버튼, 카드, 네비게이션 바 등)를 제공합니다. 사용자는 그 컴포넌트의 클래스(btn btn-primary
)를 사용하고, 커스터마이징이 비교적 어렵습니다.
-
Tailwind: 컴포넌트를 제공하지 않습니다. 대신 그 컴포넌트를 만들 수 있는 원자적인 도구(유틸리티 클래스)를 제공합니다. 따라서 훨씬 더 자유롭고 일관된 디자인이 가능합니다.
결론: Tailwind는 "디자인을 어떻게 만드는지"에 대한 도구(방법론)입니다.
2. shadcn/ui: 재사용 가능한 컴포넌트 컬렉션
간단히 말하면: Tailwind CSS와 Radix UI를 기반으로 만들어져, 복사 & 붙여넣기 방식으로 사용할 수 있는 아름답고 접근성까지 고려된 컴포넌트들의 모음집입니다.
핵심 개념:
-
컴포넌트 라이브러리가 아닙니다: 전통적인 npm 패키지(예: MUI, Chakra UI)와 다릅니다. npm install
로 설치하는 게 아니라, 컴포넌트 코드를 직접 내 프로젝트로 가져옵니다(copy & paste).
-
완전한 커스터마이징: 컴포넌트가 내 프로젝트의 소스 코드의 일부가 되기 때문에, 모든 부분을 마음대로 수정할 수 있습니다. 버전 업데이트에 구애받지 않습니다.
-
Tailwind 기반: 모든 컴포넌트가 Tailwind 클래스로 스타일링되어 있어, Tailwind의 장점(커스터마이징, 일관성)을 그대로 누릴 수 있습니다.
-
접근성(A11Y) 고려: Radix UI의 Primitives를 기반으로 만들어져 키보드 네비게이션, 스크린 리더 지원 등이 기본으로 탑재되어 있습니다.
-
대화형 CLI 도구: npx shadcn-ui@latest add [component-name]
명령어로 필요한 컴포넌트를 쉽게 프로젝트에 추가할 수 있습니다.
결론: shadcn/ui는 "미리 잘 만들어진 컴포넌트들은 무엇이 있는지"를 제공합니다. 이 컴포넌트들은 Tailwind로 만들어졌습니다.
둘의 관계: 완벽한 시너지
"Tailwind로 디자인하는 방법을 제공하고, shadcn/ui가 그 방법으로 미리 만들어놓은 예시(컴포넌트)를 제공한다"고 보시면 됩니다.
-
기본 스타일링은 Tailwind로: 프로젝트의 기본 디자인 시스템(색상, 간격, 폰트)은 Tailwind의 설정 파일로 정의합니다.
-
복잡한 컴포넌트는 shadcn/ui로: 버튼, 폼, 모달, 드롭다운 등 복잡하고 반복적인 UI 컴포넌트는 shadcn/ui에서 가져와서 시간을 절약합니다.
-
커스터마이징은 자유롭게: shadcn/ui로 가져온 컴포넌트도 내 프로젝트의 일부이기 때문에, Tailwind 클래스를 직접 수정하여 내 디자인 시스템에 완전히 맞출 수 있습니다.
예시: 버튼 만들기
-
Tailwind만 사용: <button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
-
shadcn/ui 사용: npx shadcn-ui@latest add button
명령어로 Button 컴포넌트를 추가한 후, <Button variant="default">Click</Button>
这样 사용합니다. 이 Button 컴포넌트의 내부를 보면 역시 Tailwind 클래스로 이루어져 있어 필요시 직접 수정할 수 있습니다.
요약
구분 |
Tailwind CSS |
shadcn/ui |
정의 |
CSS 프레임워크 (디자인 도구) |
컴포넌트 컬렉션 (재사용 UI 부품) |
방식 |
유틸리티 클래스를 HTML에 조합 |
컴포넌트 코드를 프로젝트에 복사 |
목적 |
디자인하는 방법을 제공 |
미리 만들어진 디자인(컴포넌트)을 제공 |
커스터마이징 |
설정 파일과 클래스 조합으로 가능 |
소스 코드 자체를 수정 가능 |
의존성 |
shadcn/ui의 기반 |
Tailwind CSS와 Radix UI에 의존 |
따라서, 두 기술은 대체제가 아니라 함께 사용하면 시너지를 내는 최고의 조합 중 하나입니다. 현대적인 React, Next.js, Astro 등과 같은 프레임워크 프로젝트에서 아주 널리 사용되고 있습니다.
Radix UI 가 뭐야?
아, Radix UI는 정말 중요한 개념이에요! shadcn/ui를 이해하는 데 핵심이 됩니다.
Radix UI: 프리미티브(Primitives) 컴포넌트 라이브러리
간단히 말하면: 접근성(Accessibility)과 상호작용 로직이 이미 완벽하게 built-in된, 스타일이 없는(raw) '뼈대' 컴포넌트들의 모음입니다. "Unstyled"라는 점이 가장 큰 특징입니다.
1. 핵심 아이디어: 분리 (Separation of Concerns)
Radix UI는 하나의 컴포넌트를 두 부분으로 분리합니다.
-
상호작용 로직 & 접근성 (Radix의 역할)
-
동작: 컴포넌트가 어떻게 작동해야 하는지에 대한 모든 복잡한 JavaScript 로직을 처리합니다. (예: 드롭다운 메뉴를 열고 닫는 상태 관리, 키보드 네비게이션, 포커스 트랩, 모달 배경 클릭 시 닫기 등)
-
접근성(A11Y): WCAG 가이드라인을 준수하여 스크린 리더 사용자, 키보드만 사용하는 사용자 등 모든 사용자가 사용할 수 있도록 보장합니다. 이 부분은 구현이 매우 까다롭고 많은 노하우가 필요합니다.
-
스타일링 (개발자의 역할)
-
외관: 컴포넌트가 어떻게 생겼는지는 완전히 여러분의 손에 맡깁니다. Radix는 클래스명이나 CSS 변수를 제공하기만 하고, 여러분이 원하는 어떤 방식으로든(CSS, Sass, Styled Components, Tailwind CSS 등) 스타일을 입힐 수 있습니다.
2. 왜 이런 방식을 채택했을까? (장점)
-
접근성 보장: Radix 팀이 접근성 전문가처럼 동작 로직을 미리 완벽하게 만들어두었기 때문에, 개발자는 스타일만 신경 쓰면 됩니다. 이는 엄청난 생산성 향상과 버그 방지로 이어집니다.
-
완벽한 디자인 자유도: 스타일이 전혀 정해져 있지 않기 때문에, 기존의 디자인 시스템(예: Bootstrap, MUI)처럼 특정 "look and feel"에 갇히지 않습니다. 우리 회사의 브랜드 디자인에 100% 맞게 컴포넌트를 꾸밀 수 있습니다.
-
컴포넌트의 품질: Radix가 제공하는 컴포넌트들은 모달(Dialog), 드롭다운 메뉴(Dropdown Menu), 툴팁(Tooltip), 토글(Toast) 등 구현이 inherently 복잡한 것들 위주입니다. 이런 것들을 직접 처음부터 만들면 시간도 오래 걸리고 버그와 접근성 문제가 발생하기 쉽습니다.
Radix UI, shadcn/ui, Tailwind CSS의 관계
이제 이 세 가지의 관계가 명확해집니다.
-
Radix UI가 뼈대와 두뇌를 제공합니다.
-
Tailwind CSS가 옷과 외모를 제공합니다.
-
shadcn/ui는 Radix(뼈대) + Tailwind(옷)의 멋진 조합을 미리 만들어 놓은 예시입니다.
요약
구분 |
역할 |
비유 |
Radix UI |
접근성과 로직에 특화된 Unstyled 컴포넌트 |
자동차의 차대(섀시)와 엔진 (달리고, 멈추는 기능은 완벽하지만 외관은 없음) |
Tailwind CSS |
디자인을 입히는 유틸리티 도구 |
도장, 인테리어, 부품을 조립하는 도구 |
shadcn/ui |
Radix + Tailwind로 미리 만든 스타일된 컴포넌트 예시 |
Radix(차대)에 Tailwind(도장/도구)로 만든 完品 자동차. 내 garage(프로젝트)로 가져와서 마음대로 도장 다시 칠할 수 있음. |
결론적으로, shadcn/ui는 Radix UI의 강력한 기능과 Tailwind CSS의 스타일링 유연성을 결합하기 위한 최고의 브릿지(Bridge) 역할을 한다고 볼 수 있습니다. Radix가 없었다면 shadcn/ui는 접근성과 복잡한 로직을 직접 모두 구현해야 하는 엄청난 부담을 안았을 것입니다.
Radix UI 자체에서도 컴포넌트를 제공하는데 shadcn/ui 와 차이는?
훌륭한 질문이에요! Radix UI 자체에서도 스타일이 입혀진 컴포넌트를 제공하기 때문에(shadcn/ui와 유사해 보일 수 있음), 둘의 차이점을 명확히 이해하는 것이 중요합니다.
결론부터 말하면, 근본적인 제공 방식과 철학에서 큰 차이가 있습니다.
Radix UI의 공식 컴포넌트 (Themes)
Radix UI는 사실 두 가지 제품을 제공합니다:
-
Radix Primitives: 스타일이 전혀 없는, 순수하게 로직과 접근성에만 집중한 뼈대 컴포넌트 (우리가 앞서討論한 것).
-
Radix Themes: Radix Primitives를 기반으로 공식에서 미리 스타일을 입혀 제공하는 컴포넌트 라이브러리.
Radix Themes와 shadcn/ui의 차이점을 표로 한눈에 비교해보겠습니다.
구분 |
Radix Themes (공식) |
shadcn/ui |
제공 방식 |
npm 패키지 (@radix-ui/themes ) |
코드 복사/붙여넣기 (또는 CLI로 파일 생성) |
설치 및 업데이트 |
npm install 로 설치, npm update 로 업데이트 |
컴포넌트 파일을 직접 프로젝트에 복사. 업데이트는 수동 |
의존성 |
프로젝트의 node_modules 에 의존성으로 존재 |
의존성 없음. 컴포넌트 코드가 내 프로젝트 소스의 일부가 됨 |
커스터마이징 |
제한적. 공식에서 제공하는 Theme 변수(색, 폰트, 간격)와 CSS 변수로만 변경 가능 |
완전한 자유. 컴포넌트의 TSX와 Tailwind 클래스를 직접 수정 가능 |
설계 철학 |
"Opinionated" (주관이 있는)
공식의 특정 디자인 시스템(라운드 코너, 특정 색상)에 따름 |
"Unopinionated" (주관이 없는)
내가 가진 Tailwind 설정과 디자인 시스템을 그대로 반영 |
번들 크기 |
전체 패키지를 번들에 포함 |
내가 사용한 컴포넌트 코드만 번들에 포함 (Tree-shaking이 아닌, 아예 코드가 없음) |
핵심 차이를 비유로 이해하기
어떤 걸 선택해야 할까?
결론
Radix Themes는 '제품'이라면, shadcn/ui는 '제품을 만들기 위한 베이스 킷(Kit)'에 가깝습니다.
shadcn/ui는 Radix Primitives의 강력한 엔진을 그대로 가져오면서, 그 위에 Tailwind라는 도구를 통해 완전한 자유도를 부여하는 하이브리드 형태의 독특한 접근법을 제시합니다. 이것이 바로 shadcn/ui가 단순한 또 하나의 컴포넌트 라이브러리가 아닌, 새로운 패러다임으로 주목받는 이유입니다.
React Aria 는 또 뭐야?
React Aria는 Adobe에서 만든 React용 라이브러리로, 접근성(a11y)과 사용자 상호작용(behavior)에 특화된 low-level 훅(Hooks)의 컬렉션입니다. Radix UI와 같은 범주에 속하지만, 접근 방식과 철학에서 뚜렷한 차이점이 있습니다.
React Aria: 상호작용과 접근성을 위한 헤드리스 훅(Headless Hooks)
간단히 말하면: 스타일은 전혀 제공하지 않고, 컴포넌트의 동작(behavior), 상태 관리, 그리고 가장 중요한 '접근성'을 구현하기 위한 React Hooks를 제공하는 라이브러리입니다. 사용자는 이 훅들이 반환하는 props를 자신이 만든 JSX 요소에 연결만 하면 됩니다.
핵심 특징
-
Hooks 기반 아키텍처: 컴포넌트가 아닌 훅(useButton
, useMenu
, useDialog
등) 을 제공합니다. 이 훅들은 상태, 이벤트 핸들러, 접근성 속성(ARIA attributes) 등을 객체로 반환합니다.
-
완전한 Headless(스타일 없음): Radix Primitives와 마찬가지로 스타일링에 대한 어떠한 가정도 하지 않습니다. 순수하게 로직과 접근성만 관리합니다.
-
격리된 상호작용 로직: 복잡한 상호작용 패턴(예: 드래그 앤 드롭, 키보드 네비게이션, 터치 이벤트 처리)을 매우 잘게 쪼개서 제공합니다. 필요한 훅만 조합해 사용할 수 있습니다.
-
국제화(i18n) 지원: 특히 우측에서 좌측으로 읽는 언어(RTL, like Arabic)를 완벽하게 지원하는 등 글로벌 애플리케이션을 구축하는 데 강점을 가집니다.
작동 방식 예시: useButton
훅
React Aria의 방식은 "훅이 props를 제공하면, 내가 그 props를 DOM 요소에 붙인다"입니다.
jsx
import { useButton } from 'react-aria';
import { useRef } from 'react';
function MyButton(props) {
let ref = useRef();
// useButton 훅이 button에 필요한 모든 props를 생성해줍니다.
let { buttonProps, isPressed } = useButton(props, ref);
return (
<button
{...buttonProps} // <-- 생성된 props(이벤트, 접근성 속성 등)를 spread
ref={ref}
className={`my-custom-class ${isPressed ? 'pressed' : ''}`}
>
{props.children}
</button>
);
}
// 사용
<MyButton onPress={() => alert('Pressed!')}>Click Me</MyButton>
-
useButton
은 onClick
핸들러, tabIndex
, role
, aria-*
속성, 키보드 이벤트 처리 로직 등을 buttonProps
객체에 담아 반환합니다.
-
isPressed
같은 상태값도 제공하여, pressed 상태에 따른 스타일을 적용할 수 있게 해줍니다.
-
개발자는 반환된 props를 원하는 DOM 요소(<button>
, <div>
)에 연결하고, 자신이 원하는 방식으로 스타일(my-custom-class
)을 적용하면 됩니다.
React Aria vs. Radix UI Primitives
둘 다 "Headless" 접근법을 취하지만, 구현 방식과 초점이 다릅니다.
구분 |
React Aria (Adobe) |
Radix UI Primitives (WorkOS) |
제공 형태 |
Hooks (useButton , useMenu ) |
컴포넌트 (<DropdownMenu> , <Dialog> ) |
사용 방식 |
훅을 호출해 반환된 props를 DOM에 spread |
JSX 컴포넌트를 조합하여 사용 |
설계 철학 |
Fine-grained(세분화된): 아주 작은 단위의 훅을 제공하고 필요시 조합하도록 유도 |
Batteries-included: 하나의 컴포넌트가 해당 UI의 모든 복잡성을 캡슐화 (예: <DropdownMenu> 하나면 드롭다운 완성) |
초점 |
상호작용과 국제화(i18n)에 매우 강력한 초점 |
접근성에 초점, React Aria보다는 더 높은 수준의 추상화 |
학습 곡선 |
훅과 반환되는 props를 이해해야 해서 초보자에게 다소 낮은 접근성 |
JSX로 직관적으로 사용 가능해 상대적으로 진입 장벽이 낮음 |
React Aria, shadcn/ui, Tailwind와의 관계
React Aria는 Radix Primitives와 동일한 '뼈대' 역할을 하는 또 다른 선택지입니다.
-
React Aria + Tailwind CSS: React Aria의 훅으로 동작과 접근성을 구현하고, Tailwind로 완전히 자유롭게 스타일링하는 패턴이 매우 강력합니다. 이 조합은 완전한 자유도와 전문적인 결과물을 원하는 개발자들에게極히 인기가 있습니다.
-
shadcn/ui와의 관계: shadcn/ui는 현재는 주로 Radix UI를 뼈대로 선택했습니다. 하지만 이론적으로는 React Aria 훅을 사용해 컴포넌트를再造作하는 것도 가능합니다. shadcn/ui의 철학은 "뼈대" 자체가 아니라 "뼈대 + Tailwind 스타일의 예시"를 제공하는 것이기 때문입니다.
요약 및 비유
-
React Aria: 자동차의 각종 전자 제어 장치(ECU)와 센서 세트를 제공합니다. 이 부품들을 조합하면 엔진이 어떻게 작동해야 할지, 문이 어떻게 잠겨야 할지에 대한 '로직'을 완성할 수 있습니다. 최종 외관은 내가 직접 디자인합니다.
-
Radix UI: 잘 만들어진 엔진과 섀시의 조합을 제공합니다. ECU와 센서는 이미 그 안에 내장되어 있어서, 가져다가 외관만 만들면 됩니다.
React Aria를 선택할 때는?
-
Radix가 제공하지 않는 매우 특수한 상호작용이 필요할 때.
-
RTL을 포함한 국제화(i18n) 지원이 프로젝트의 핵심일 때.
-
최대한의 유연성과 제어력을 원하고, Hooks 패턴을 선호할 때.
-
Adobe의 Design System(React Spectrum)처럼 매우大规模이고 복잡한 디자인 시스템을 구축할 때. (React Aria는 실제로 React Spectrum을 위해 만들어졌습니다)