프론트엔드 개발하다 보면 UI 컴포넌트 만들 때 고민이 많죠? 재사용 가능하게 만들어야 하고, 키보드만으로도 쓸 수 있게 접근성도 신경 써야 하고... 요구 사항이 한두 가지가 아니잖아요. 😅
이런 고민을 덜어주기 위해 등장한 멋진 친구가 있어요! 바로 Radix UI Primitives인데요, 얘는 접근성 좋은 UI 컴포넌트 뼈대(Primitives)를 제공해서 우리가 직접 디자인 시스템을 쉽게 만들 수 있도록 도와주는 라이브러리예요. 스타일은 전혀 없고 기능에만 집중한 기본 부품들이라고 생각하면 좋아요! 요즘 정말 핫한 shadcn/ui
같은 멋진 UI 라이브러리들도 바로 이 Radix UI를 기반으로 만들어졌다는 사실, 알고 계셨나요? 그만큼 기본기가 탄탄하다는 증거겠죠! ✨
오늘은 이 Radix UI Primitives가 뭔지, 어떻게 사용하는지 기본적인 개념과 간단한 예제를 통해 알아볼게요! 😉
쉽게 말해서, 접근성을 아주 잘 갖춘 기본적인 UI 컴포넌트 기능 모음집이에요. 다이얼로그(팝업), 툴팁, 탭 같은 것들의 핵심 기능만 딱! 들어있죠.
가장 큰 특징은 스타일이 전혀 없다는 거예요! 😮 우리가 CSS든, Tailwind CSS든, styled-components든 원하는 방식으로 처음부터 끝까지 직접 꾸며야 해요. 디자인 시스템을 직접 구축하거나 아주 세밀하게 커스텀하고 싶을 때 정말 유용하겠죠?
설치는 아주 간단해요! npm이나 yarn 같은 패키지 매니저로 뚝딱 설치할 수 있답니다.
# npm 사용자라면
npm install @radix-ui/react-dialog @radix-ui/react-tooltip @radix-ui/react-tabs
# (예제에서 사용할 패키지들을 한번에 설치하는 예시예요. 필요한 것만 골라서 설치해도 돼요!)
# yarn 사용자라면
yarn add @radix-ui/react-dialog @radix-ui/react-tooltip @radix-ui/react-tabs
(참고 Radix UI는 각 컴포넌트별로 패키지가 나뉘어 있어요. @radix-ui/react-dialog
, @radix-ui/react-tooltip
이런 식으로 필요한 컴포넌트 패키지를 설치해주면 돼요!)
가장 기본적인 예제로 다이얼로그(흔히 말하는 팝업창!) 컴포넌트를 만들어 볼게요. 사용자에게 메시지를 보여주거나 추가 정보를 입력받을 때 많이 쓰죠.
import React from 'react';
import * as DialogPrimitive from '@radix-ui/react-dialog';
// 기본적인 Dialog 예제 (스타일은 직접 입혀야 해요!)
export default function MyDialog() {
return (
// 1. Dialog의 전체 영역을 감싸는 Root 컴포넌트예요. 얘가 대장!
<DialogPrimitive.Root>
{/* 2. 이 버튼을 누르면 Dialog가 열려요. Trigger(방아쇠) 역할! */}
<DialogPrimitive.Trigger asChild>
<button className="my-button-style">다이얼로그 열기</button>
{/* asChild는 스타일링을 위해 내부 버튼을 사용하겠다는 의미예요 */}
</DialogPrimitive.Trigger>
{/* Dialog가 열렸을 때 보이는 내용을 관리하는 Portal */}
{/* Portal을 사용하면 DOM 트리 상에서 다른 위치에 렌더링할 수 있어요 (보통 body 바로 아래) */}
<DialogPrimitive.Portal>
{/* 배경 어둡게 처리하는 Overlay */}
<DialogPrimitive.Overlay className="my-overlay-style" />
{/* 3. Dialog의 실제 내용이 들어가는 곳! */}
<DialogPrimitive.Content className="my-content-style">
<DialogPrimitive.Title className="my-title-style">
안녕하세요!
</DialogPrimitive.Title>
<DialogPrimitive.Description className="my-desc-style">
여기는 다이얼로그 내용이에요. 원하는 내용을 자유롭게 넣을 수 있답니다.
</DialogPrimitive.Description>
{/* 닫기 버튼 */}
<DialogPrimitive.Close asChild>
<button className="my-close-button-style">닫기</button>
</DialogPrimitive.Close>
</DialogPrimitive.Content>
</DialogPrimitive.Portal>
</DialogPrimitive.Root>
);
}
// 여기에 my-button-style, my-overlay-style 같은 CSS 클래스 스타일을 직접 정의해야
// 화면에 예쁘게 보여요! Radix는 기능만 제공할 뿐, 모양은 우리가 만들어야 해요.
Radix UI 컴포넌트들은 이렇게 Root
, Trigger
, Content
, Portal
, Overlay
, Close
등 역할별로 컴포넌트가 잘 나뉘어 있어요. 우리는 이 뼈대들을 조립하고 스타일만 입히면 되는 거죠! 접근성 관련 기능(키보드 탐색, 포커스 관리 등)은 Radix가 알아서 처리해주니 정말 편해요.
툴팁은 버튼이나 아이콘 위에 마우스를 올렸을 때 잠깐 나타나서 부가 설명을 보여주는 작은 말풍선 같은 거죠. Radix UI로 툴팁도 쉽게 만들 수 있어요.
import React from 'react';
import * as TooltipPrimitive from '@radix-ui/react-tooltip';
// 기본적인 Tooltip 예제 (역시 스타일은 직접!)
export default function MyTooltip() {
return (
// Tooltip을 사용하려면 Provider로 먼저 감싸줘야 해요.
<TooltipPrimitive.Provider delayDuration={300}> {/* 나타나는 딜레이 설정 */}
{/* 1. 툴팁의 전체 영역 Root */}
<TooltipPrimitive.Root>
{/* 2. 마우스를 올리면 툴팁이 나타날 요소 (버튼 등) */}
<TooltipPrimitive.Trigger asChild>
<button className="my-icon-button-style">?</button>
</TooltipPrimitive.Trigger>
{/* 툴팁 내용 Portal */}
<TooltipPrimitive.Portal>
{/* 3. 툴팁의 실제 내용 + 화살표 */}
<TooltipPrimitive.Content className="my-tooltip-content-style" sideOffset={5}>
여기에 도움말 내용을 적어주세요!
{/* 툴팁 꼬리표(화살표)도 쉽게 추가 가능해요 */}
<TooltipPrimitive.Arrow className="my-tooltip-arrow-style" />
</TooltipPrimitive.Content>
</TooltipPrimitive.Portal>
</TooltipPrimitive.Root>
</TooltipPrimitive.Provider>
);
}
// 여기서도 my-icon-button-style, my-tooltip-content-style 등의 스타일을 직접 만들어야 해요!
다이얼로그랑 구조가 비슷하죠? Root
, Trigger
, Content
가 핵심이고, 필요에 따라 Provider
, Portal
, Arrow
같은 부가 컴포넌트들을 사용하면 돼요.
이번엔 여러 콘텐츠 섹션을 깔끔하게 보여주는 탭(Tabs) 컴포넌트를 만들어 볼게요. 이건 부품이 조금 더 많아요!
import React from 'react';
import * as TabsPrimitive from '@radix-ui/react-tabs';
// 기본적인 Tabs 예제 (스타일 필요!)
export default function MyTabs() {
return (
// 1. 탭 전체를 감싸는 Root, defaultValue로 처음 보여줄 탭 지정
<TabsPrimitive.Root className="my-tabs-root-style" defaultValue="tab1">
{/* 2. 탭 버튼들을 묶어주는 List */}
<TabsPrimitive.List className="my-tabs-list-style" aria-label="정보 섹션">
{/* 3. 각 탭 버튼 Trigger, value로 어떤 Content와 연결될지 지정 */}
<TabsPrimitive.Trigger className="my-tab-trigger-style" value="tab1">
정보 1
</TabsPrimitive.Trigger>
<TabsPrimitive.Trigger className="my-tab-trigger-style" value="tab2">
정보 2
</TabsPrimitive.Trigger>
</TabsPrimitive.List>
{/* 4. 각 탭을 눌렀을 때 보여줄 내용 Content, value로 어떤 Trigger와 연결될지 지정 */}
<TabsPrimitive.Content className="my-tab-content-style" value="tab1">
<p>여기는 정보 1 섹션의 내용입니다.</p>
</TabsPrimitive.Content>
<TabsPrimitive.Content className="my-tab-content-style" value="tab2">
<p>저기는 정보 2 섹션의 내용이고요!</p>
</TabsPrimitive.Content>
</TabsPrimitive.Root>
);
}
// my-tabs-root-style, my-tabs-list-style 등의 스타일 정의가 필요해요!
Root
안에 탭 버튼들을 모아두는 List
가 있고, 각 탭 버튼은 Trigger
로 만들어요. 그리고 각 탭에 해당하는 내용은 Content
컴포넌트로 만들죠. Trigger
와 Content
는 value
속성값을 기준으로 서로 연결돼서, 해당 value
를 가진 Trigger
를 누르면 같은 value
를 가진 Content
가 보이게 된답니다.
Radix UI Primitives는 스타일은 쏙 빠지고 기능과 접근성에만 집중한 로우 레벨 UI 컴포넌트 뼈대를 제공하는 멋진 라이브러리예요.
오늘 살펴본 다이얼로그, 툴팁, 탭 예제만 봐도 Radix UI가 얼마나 유연하고 강력한지 느낄 수 있죠? 복잡한 UI 인터랙션과 접근성을 직접 구현하는 대신, Radix UI가 제공하는 뼈대를 활용하고 우리는 스타일에만 집중하면 되니 개발 생산성이 확 올라갈 거예요!
Radix UI가 얼마나 강력한 기반이 되어주는지는 요즘 개발자들 사이에서 폭발적인 인기를 얻고 있는 shadcn/ui
를 보면 바로 알 수 있어요. shadcn/ui
는 바로 이 Radix UI의 기능 뼈대 위에 Tailwind CSS로 멋지게 스타일을 입힌 라이브러리거든요! 🤩 Radix UI가 제공하는 탄탄한 접근성과 기능 덕분에 shadcn/ui
같은 멋진 결과물이 나올 수 있었던 거죠.
나만의 개성 있는 UI 컴포넌트를 만들고 싶다면, Radix UI Primitives를 꼭 한번 사용해보세요! 👍