Radix UI vs Headless UI vs Ark UI: что брать
Headless-библиотеки компонентов — это инструмент, который решает одну задачу: даёт корректное поведение и доступность, не навязывая стилизацию. Их в 2026 году осталось три заметных: Radix UI, Headless UI и Ark UI. Я работал со всеми тремя в продакшене и в разное время выбирал каждую по своим причинам. Расскажу, в чём разница, и что важно для проектного выбора.
В одну строку про каждую
Radix UI — самый зрелый, обширный и стабильный набор примитивов для React. Foundation для shadcn/ui.
Headless UI — компактная библиотека от команды Tailwind. Покрывает базовые компоненты (combobox, dialog, listbox, popover) и тесно интегрирована с Tailwind.
Ark UI — мульти-фреймворковая (React, Vue, Solid) библиотека на основе state-machines от Zag.js. Самый молодой и активный проект.
Что общего
- Все три не навязывают стили. Ты получаешь поведение и accessibility, дизайн делаешь сам.
- Все три закрывают a11y по WAI-ARIA APG.
- Все три поддерживают типизацию TypeScript.
- Все три играют хорошо вместе с Tailwind, CSS Modules, styled-components — без разницы.
Сценарии, где я беру Radix
Когда мне нужен зрелый набор компонентов для большого React-проекта. Radix покрывает почти всё: Dialog, DropdownMenu, ContextMenu, Tooltip, Popover, Tabs, Accordion, Toast, Slider, Switch, Toggle, Select, Combobox, NavigationMenu, ToggleGroup, RadioGroup, ScrollArea — список длинный.
import * as Dialog from '@radix-ui/react-dialog';
export function Modal({ open, onOpenChange, children }) {
return (
<Dialog.Root open={open} onOpenChange={onOpenChange}>
<Dialog.Portal>
<Dialog.Overlay className="fixed inset-0 bg-black/40" />
<Dialog.Content className="fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-white p-6 rounded">
{children}
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
);
}API чёткий, документация полноценная, поведение под капотом покрывает все edge-cases по a11y. Я в продах беру Radix без раздумий, если нужен серьёзный набор.
Сценарии, где я беру Headless UI
На небольших проектах с Tailwind, где нужно несколько простых компонентов: модалка, dropdown, combobox. Headless UI компактнее, его API чуть чище для типичных сценариев, и он отлично знает, что вы используете Tailwind.
import { Dialog, Transition } from '@headlessui/react';
import { Fragment } from 'react';
export function Modal({ open, onClose, children }) {
return (
<Transition show={open} as={Fragment}>
<Dialog onClose={onClose} className="relative z-50">
<Transition.Child as={Fragment} enter="ease-out duration-200" enterFrom="opacity-0" enterTo="opacity-100">
<div className="fixed inset-0 bg-black/40" />
</Transition.Child>
<Dialog.Panel className="fixed inset-0 flex items-center justify-center p-4">
<div className="bg-white rounded p-6 max-w-md w-full">{children}</div>
</Dialog.Panel>
</Dialog>
</Transition>
);
}Из плюсов: встроенный Transition, который удобно стыкуется с Tailwind. Из минусов: набор компонентов меньше Radix, нет сложных штук вроде ScrollArea, ContextMenu, NavigationMenu.
Сценарии, где я беру Ark UI
Когда работаю одновременно в нескольких фреймворках. У меня был кейс: дизайн-система для компании, где фронт частично на React (продукт), частично на Vue (админка), частично на Solid (внутренний инструмент). Radix и Headless UI работают только с React. Ark UI — со всеми тремя.
Ark — это унифицированная обёртка над state-machines (Zag.js). Поведение одинаковое, API адаптируется под фреймворк. Я смог реализовать общую дизайн-систему один раз и переиспользовать её во всех трёх стеках.
import { Dialog } from '@ark-ui/react';
export function Modal() {
return (
<Dialog.Root>
<Dialog.Trigger>Открыть</Dialog.Trigger>
<Dialog.Backdrop className="fixed inset-0 bg-black/40" />
<Dialog.Positioner className="fixed inset-0 grid place-items-center">
<Dialog.Content className="bg-white rounded p-6 max-w-md">
<Dialog.Title>Заголовок</Dialog.Title>
<Dialog.Description>Описание</Dialog.Description>
<Dialog.CloseTrigger>×</Dialog.CloseTrigger>
</Dialog.Content>
</Dialog.Positioner>
</Dialog.Root>
);
}API близкий к Radix. У Ark больше «частей» в композиции (Positioner, Backdrop, CloseTrigger), что местами избыточно. Зато детальнее можно стилизовать.
Сравнение по реальным задачам
Я не делаю таблиц, поэтому пройдусь по сценариям.
Сложные модалки и dialog
Radix и Ark — на одном уровне, оба отлично работают. Headless UI — справляется, но с более ограниченным API.
Combobox с асинхронной подгрузкой
Radix Combobox (точнее Select с поиском) — работает, но без асинхронности из коробки. Headless UI Combobox — встроен, простой и удобный для асинхронных опций. Ark UI Combobox — тоже есть, и сильнее настраивается.
NavigationMenu
Только Radix имеет полноценный NavigationMenu. Это специфический компонент с горизонтальной навигацией, выпадающими подменю и a11y по APG. У Headless UI и Ark такого нет — нужно собирать руками.
ScrollArea
Radix имеет ScrollArea — кастомный скроллбар, который работает кросс-браузерно. У Headless UI нет, у Ark — на момент написания не нашёл.
ContextMenu
Только Radix. Ни у Headless UI, ни у Ark нет правого клика «из коробки».
Производительность и размер
Radix больше всех по итоговому весу — но это распределено по компонентам, и tree-shaking работает. На обычном продукте, где используется 6-8 компонентов, бандл будет 20-30 КБ gzip.
Headless UI — компактнее всех. Это ощущается на лендингах с одной модалкой.
Ark UI — за счёт state-machines имеет немного больший рантайм, но в обмен — единое поведение и расширяемые внутренние состояния. На продакшен-приложении разница в десятки килобайт, не критично.
Какой бы я выбирал
- React + большая система: Radix. Самый зрелый, самый покрытый, лучший a11y из коробки.
- React + Tailwind + базовые потребности: Headless UI. Меньше зависимости, простой API, отличные транзиции.
- Несколько фреймворков: Ark UI. Общая платформа на React, Vue, Solid.
- Сложные навигации, скроллбары, контекстные меню: Radix. Без вариантов.
Что важно при выборе
Поддержка авторами. Radix развивается стабильно, у него огромное коммьюнити (включая shadcn/ui). Headless UI обновляется реже, но хорошо поддерживается командой Tailwind. Ark UI самый активный, выпускают по релизу в неделю-две.
Ловушка: если выбрал библиотеку «для прода», заменить позже сложно. Все три используют разные API-конвенции, и переезд между ними — это переписывать обёртки. Поэтому первый выбор — серьёзный.
Что копать дальше
Если ты только начинаешь дизайн-систему — поставь себе одну headless-библиотеку, заверни в свои компоненты с понятными именами (UiModal, UiDropdown) и используй их везде. Так ты не зависишь от конкретного API на каждом use-кейсе и сможешь поменять реализацию, если понадобится. Это занимает день дополнительной работы — окупается на длинной дистанции.