lenec ru

← все посты

Radix UI vs Headless UI vs Ark UI: что брать

11K

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-кейсе и сможешь поменять реализацию, если понадобится. Это занимает день дополнительной работы — окупается на длинной дистанции.

Комментарии 0

  • Будьте первым, кто оставит комментарий.

Войдите, чтобы оставить комментарий.