프론트엔드 개발하다 보면 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를 꼭 한번 사용해보세요! 👍