Radix UI Primitives 소개
Radix UI는 접근성(a11y)이 완벽하게 구현된 헤드리스 UI 컴포넌트 라이브러리입니다. 스타일이 전혀 없어서 완전한 디자인 자유도를 제공하면서도, WAI-ARIA 패턴을 모두 준수합니다.
Dialog 컴포넌트 커스터마이징
import * as Dialog from '@radix-ui/react-dialog';
import { X } from 'lucide-react';
export function Modal({ trigger, title, children }) {
return (
<Dialog.Root>
<Dialog.Trigger asChild>
{trigger}
</Dialog.Trigger>
<Dialog.Portal>
<Dialog.Overlay className="fixed inset-0 bg-black/50
data-[state=open]:animate-in data-[state=open]:fade-in-0
data-[state=closed]:animate-out data-[state=closed]:fade-out-0"
/>
<Dialog.Content className="fixed left-1/2 top-1/2
-translate-x-1/2 -translate-y-1/2
w-full max-w-lg rounded-xl bg-white p-6 shadow-xl
data-[state=open]:animate-in data-[state=open]:fade-in-0
data-[state=open]:zoom-in-95">
<Dialog.Title className="text-lg font-semibold">
{title}
</Dialog.Title>
<div className="mt-4">{children}</div>
<Dialog.Close asChild>
<button className="absolute right-4 top-4 rounded-sm
opacity-70 hover:opacity-100" aria-label="닫기">
<X className="h-4 w-4" />
</button>
</Dialog.Close>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
);
}
Select 컴포넌트
import * as Select from '@radix-ui/react-select';
import { ChevronDown, Check } from 'lucide-react';
export function CustomSelect({ options, placeholder, value, onChange }) {
return (
<Select.Root value={value} onValueChange={onChange}>
<Select.Trigger className="inline-flex items-center justify-between
rounded-lg border border-gray-300 px-3 py-2 text-sm
hover:border-gray-400 focus:outline-none focus:ring-2
focus:ring-blue-500 min-w-[200px]">
<Select.Value placeholder={placeholder} />
<Select.Icon>
<ChevronDown className="h-4 w-4 opacity-50" />
</Select.Icon>
</Select.Trigger>
<Select.Portal>
<Select.Content className="overflow-hidden rounded-lg border
bg-white shadow-lg
data-[state=open]:animate-in data-[state=open]:fade-in-0
data-[state=open]:zoom-in-95">
<Select.Viewport className="p-1">
{options.map((opt) => (
<Select.Item key={opt.value} value={opt.value}
className="relative flex cursor-pointer items-center
rounded-md py-2 pl-8 pr-4 text-sm outline-none
data-[highlighted]:bg-blue-50 data-[highlighted]:text-blue-700">
<Select.ItemIndicator className="absolute left-2">
<Check className="h-4 w-4" />
</Select.ItemIndicator>
<Select.ItemText>{opt.label}</Select.ItemText>
</Select.Item>
))}
</Select.Viewport>
</Select.Content>
</Select.Portal>
</Select.Root>
);
}
Tooltip 컴포넌트
import * as Tooltip from '@radix-ui/react-tooltip';
export function TooltipWrapper({ children, content, side = 'top' }) {
return (
<Tooltip.Provider delayDuration={200}>
<Tooltip.Root>
<Tooltip.Trigger asChild>
{children}
</Tooltip.Trigger>
<Tooltip.Portal>
<Tooltip.Content side={side} sideOffset={5}
className="z-50 rounded-md bg-gray-900 px-3 py-1.5
text-xs text-white shadow-md
animate-in fade-in-0 zoom-in-95">
{content}
<Tooltip.Arrow className="fill-gray-900" />
</Tooltip.Content>
</Tooltip.Portal>
</Tooltip.Root>
</Tooltip.Provider>
);
}
data 속성 기반 스타일링
| data 속성 | Tailwind 클래스 | 의미 |
|---|---|---|
| data-state="open" | data-[state=open]:... | 열린 상태 |
| data-state="closed" | data-[state=closed]:... | 닫힌 상태 |
| data-highlighted | data-[highlighted]:... | 키보드/마우스 포커스 |
| data-disabled | data-[disabled]:... | 비활성 상태 |
- Radix UI는 shadcn/ui의 기반 라이브러리이기도 합니다
asChildprop으로 트리거 요소를 커스텀 컴포넌트로 대체할 수 있습니다- 키보드 네비게이션, 스크린 리더 지원이 기본 내장되어 있습니다
- 포커스 트랩, ESC 닫기, 외부 클릭 닫기 등 인터랙션 패턴이 완성되어 있습니다
Radix UI는 "접근성은 완벽하게, 스타일은 자유롭게"라는 철학을 실현한 라이브러리입니다. Tailwind CSS와 결합하면 빠르게 고품질 커스텀 UI를 만들 수 있습니다.
댓글 0