Headless UI란? 개념과 적용 시 주의사항
10 Mar 2025
웹 개발에서 UI 컴포넌트 라이브러리는 필수 요소입니다. 하지만, 디자인이 강하게 결합된 컴포넌트는 프로젝트마다 커스터마이징이 어려운 경우가 많습니다. 이를 해결하기 위해 등장한 개념이 Headless UI입니다.
이 글에서는 Headless UI의 개념과 탄생 배경, 대표적인 프레임워크, 적용 시 주의할 점을 정리해 보겠습니다.
1. Headless UI란?
🏗 Headless UI의 개념
Headless UI는 디자인(스타일) 없이 기능만 제공하는 UI 라이브러리를 의미합니다. 즉, UI의 동작과 상태 관리 기능을 제공하지만, 스타일은 전혀 포함하지 않거나 최소한으로 유지됩니다.
✅ 주요 특징
- 스타일이 없는 UI 컴포넌트
- 완전한 커스터마이징 가능
- 프레임워크에 독립적 (React, Vue 등 다양한 환경에서 사용 가능)
- 접근성(Accessibility, A11Y)을 고려한 컴포넌트 제공

🚀 예제
예를 들어, 일반적인 UI 라이브러리(예: Material UI, Ant Design)의 Dropdown 컴포넌트는 기본적인 스타일과 테마가 포함되어 있습니다.
하지만, Headless UI의 Dropdown은 동작과 상태 관리만 제공하고, 디자인은 사용자가 직접 스타일링해야 합니다.
import { Menu } from '@headlessui/react'
export default function Dropdown() {
return (
<Menu>
<Menu.Button>메뉴 열기</Menu.Button>
<Menu.Items>
<Menu.Item>
{({ active }) => <a className={`${active ? 'bg-blue-500' : ''}`} href="#">옵션 1</a>}
</Menu.Item>
</Menu.Items>
</Menu>
)
}
👆 위 코드에서는 Menu, Menu.Button, Menu.Items 같은 기능적 컴포넌트만 제공되고, 스타일은 직접 작성해야 합니다
2. Headless UI가 탄생한 배경
💡 UI 라이브러리의 문제점
- 디자인이 강하게 결합된 UI 컴포넌트
- 기존 UI 프레임워크(Material UI, Bootstrap 등)는 기본적인 스타일을 제공하지만, 프로젝트에 맞게 커스터마이징하기 어려움.
- 디자인 시스템이 정해진 경우, 기본 스타일을 수정하는 과정이 복잡해짐.
- 접근성(A11Y) 문제
- 직접 UI를 만들 경우, 키보드 네비게이션, ARIA 속성, 포커스 관리 등 접근성 관련 기능을 구현해야 하는 부담이 있음.
- Headless UI는 접근성을 고려한 기본 로직을 제공하므로, 개발자가 스타일에만 집중할 수 있음.
- 재사용성과 유연성 증가 필요
- 컴포넌트 라이브러리를 여러 프로젝트에서 공통으로 사용하기 위해서는, 스타일을 최소화하고 동작 로직만 제공하는 형태가 더 적합함.
- 특히, Tailwind CSS 같은 Utility-First 방식과 결합하면 효율적인 개발 가능.
3. 대표적인 Headless UI 프레임워크
현재 여러 프레임워크에서 Headless UI 패턴을 지원하는 라이브러리가 존재합니다.
🚀 1) Headless UI (Tailwind Labs)
주요 특징:
- Tailwind CSS 팀에서 개발한 라이브러리
- React 및 Vue를 지원
- Modal, Dialog, Popover, Menu 등 제공
- 접근성(A11Y) 지원이 강점
예제: @headlessui/react를 사용한 모달
import { Dialog } from '@headlessui/react'
export default function MyModal({ isOpen, setIsOpen }) {
return (
<Dialog open={isOpen} onClose={() => setIsOpen(false)}>
<Dialog.Panel>
<Dialog.Title>모달 제목</Dialog.Title>
<Dialog.Description>모달 내용</Dialog.Description>
<button onClick={() => setIsOpen(false)}>닫기</button>
</Dialog.Panel>
</Dialog>
)
}
🚀 2) Radix UI
주요 특징:
- 접근성(A11Y)이 가장 강력한 라이브러리
- Unstyled(스타일 없는) 컴포넌트 제공
- React 전용
- Dropdown, Tooltip, Dialog, Accordion, Tabs 등 다양한 UI 제공
예제: @radix-ui/react-dialog 사용
import * as Dialog from '@radix-ui/react-dialog';
export default function Example() {
return (
<Dialog.Root>
<Dialog.Trigger>Open</Dialog.Trigger>
<Dialog.Portal>
<Dialog.Overlay />
<Dialog.Content>
<Dialog.Title>Title</Dialog.Title>
<Dialog.Close>Close</Dialog.Close>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
);
}
🚀 3) Reakit
주요 특징:
- 컴포넌트 기반 접근성 지원
- 초경량(가벼운 번들 크기)
- React 전용
- 커스텀 스타일 적용이 쉽고, 다른 CSS 프레임워크와 잘 어울림
예제: @reakit/menu 사용
import { useMenuState, Menu, MenuItem, MenuButton } from "reakit/Menu";
export default function Example() {
const menu = useMenuState();
return (
<>
<MenuButton {...menu}>Open</MenuButton>
<Menu {...menu}>
<MenuItem {...menu}>옵션 1</MenuItem>
<MenuItem {...menu}>옵션 2</MenuItem>
</Menu>
</>
);
}
4. Headless UI 적용 시 주의할 점
⚠️ 1) 스타일을 직접 구현해야 함
- Headless UI는 디자인(스타일)이 없기 때문에, Tailwind CSS, Styled Components 등을 사용하여 스타일을 직접 적용해야 함.
- UI 디자인이 필요한 프로젝트에서는 Material UI 같은 라이브러리가 더 적합할 수도 있음.
⚠️ 2) 접근성(A11Y) 기본 원칙을 이해해야 함
- Headless UI 컴포넌트는 접근성(A11Y) 관련 기능을 기본 제공하지만, 올바르게 사용하지 않으면 기대한 동작을 하지 않을 수 있음.
- 예를 들어, Dialog에서 onClose를 설정하지 않으면, 키보드 접근성이 떨어질 수 있음.
⚠️ 3) 프레임워크 호환성 확인
- 대부분의 Headless UI 라이브러리는 React 전용이므로, Vue/Nuxt/Svelte와의 호환성을 반드시 확인해야 함.
🎯 스타일 없는 Headless UI 라이브러리라는 개념이 낯설다면, Tailwind CSS와 함께 사용해 보면서 익숙해지는 것이 좋습니다! 🚀
5. 결론
- ✅ Headless UI는 기능 중심의 UI 라이브러리로, 스타일을 직접 적용할 수 있는 유연성을 제공합니다.
- ✅ Radix UI, Headless UI(Tailwind Labs), Reakit 같은 라이브러리는 접근성과 기능성을 모두 고려한 컴포넌트를 제공합니다.
- ✅ 스타일링 자유도가 필요한 프로젝트에서는 Headless UI가 강력한 선택지가 될 수 있지만, 기본 디자인이 필요하다면 기존 UI 라이브러리를 고려해야 합니다.