Базовая структура компонента

Radix UI — это набор низкоуровневых, полностью настраиваемых компонентов для создания интерфейсов на React. Каждый компонент в Radix UI строится вокруг семантической структуры, что обеспечивает совместимость с доступностью (a11y) и гибкость в стилизации.

Ключевой принцип: компонент делится на три уровня:

  1. Root-компонент — контейнер, который управляет состоянием и логикой.
  2. Trigger / Control — элемент взаимодействия пользователя.
  3. Content / Portal — визуальная часть, отображающая данные или контент.

Например, для компонента Dropdown Menu структура выглядит так:

<DropdownMenu.Root>
  <DropdownMenu.Trigger>Открыть меню</DropdownMenu.Trigger>
  <DropdownMenu.Content>
    <DropdownMenu.Item>Пункт 1</DropdownMenu.Item>
    <DropdownMenu.Item>Пункт 2</DropdownMenu.Item>
  </DropdownMenu.Content>
</DropdownMenu.Root>

Здесь Root управляет состоянием открытия меню, Trigger отвечает за пользовательское взаимодействие, а Content — за визуальное отображение списка.


Root-компонент и управление состоянием

Root-компонент является сердцем компонента. Он отвечает за:

  • внутреннее состояние (open, checked, value),
  • обработку событий (например, клики вне компонента, клавиши Escape),
  • координацию дочерних элементов.

Пример для Toggle:

<Toggle.Root defaultPressed={false}>
  <Toggle.Thumb />
</Toggle.Root>
  • defaultPressed задает начальное состояние.
  • Toggle.Thumb визуализирует текущее состояние.

Root-компонент может принимать контролируемое состояние, что позволяет интегрировать компонент с внешним состоянием приложения:

const [pressed, setPressed] = useState(false);

<Toggle.Root pressed={pressed} onPressedCha nge={setPressed}>
  <Toggle.Thumb />
</Toggle.Root>

Trigger / Control: элементы взаимодействия

Trigger — это элемент, который инициирует действия пользователя. Его особенности:

  • Обеспечивает доступность, добавляя aria-* атрибуты.
  • Поддерживает клавиатурные взаимодействия по умолчанию.
  • Может быть любым HTML-элементом или компонентом React.

Пример для Dropdown Menu Trigger:

<DropdownMenu.Trigger asChild>
  <button className="menu-button">Меню</button>
</DropdownMenu.Trigger>

Использование asChild позволяет применять свой стиль к дочернему элементу без потери логики Radix UI.


Content / Portal: визуальная часть

Content отображает данные, но не управляет состоянием. Он обычно рендерится через Portal, что позволяет выводить его вне DOM-иерархии родителя, предотвращая проблемы с z-index и overflow.

Пример:

<DropdownMenu.Content side="bottom" align="start">
  <DropdownMenu.Item>Пункт 1</DropdownMenu.Item>
  <DropdownMenu.Item>Пункт 2</DropdownMenu.Item>
</DropdownMenu.Content>
  • side определяет позицию относительно Trigger (top, bottom, left, right).
  • align задает выравнивание (start, center, end).
  • Компонент автоматически добавляет фокус и обработку клавиш для доступности.

Атрибут asChild и композиция компонентов

asChild — мощный инструмент Radix UI, позволяющий:

  • передавать кастомные элементы, сохраняя логику компонента,
  • избегать лишней обертки в DOM,
  • интегрировать с любыми UI-библиотеками и стилями.

Пример использования в Tooltip:

<Tooltip.Root>
  <Tooltip.Trigger asChild>
    <button>Наведи на меня</button>
  </Tooltip.Trigger>
  <Tooltip.Content>Подсказка</Tooltip.Content>
</Tooltip.Root>

Без asChild Tooltip создавал бы собственный div, что могло бы нарушить стили или позиционирование.


Контролируемые и неконтролируемые компоненты

Radix UI поддерживает два подхода к состоянию:

  1. Неконтролируемый — компонент сам управляет состоянием. Пример: defaultOpen, defaultValue.
  2. Контролируемый — состояние задается внешне через open, value, pressed и callback-функции.

Это позволяет интегрировать компонент в приложения с глобальным состоянием, такими как Redux или Zustand, сохраняя полную предсказуемость поведения.


Доступность (A11y) и фокус

Radix UI автоматически:

  • управляет фокусом,
  • добавляет ARIA-атрибуты,
  • поддерживает клавиатурную навигацию (Tab, Arrow Keys, Escape).

Пример для Dropdown Menu:

  • ArrowDown и ArrowUp перемещают фокус между элементами,
  • Enter выбирает элемент,
  • Escape закрывает меню.

Это снижает необходимость вручную прописывать сложную логику доступности.


Стилизация и кастомизация

Radix UI не навязывает стили. Компоненты:

  • используют универсальные классы и атрибуты,
  • поддерживают CSS, CSS-in-JS и Tailwind,
  • предоставляют состояния (data-state="open", data-disabled, data-active), которые можно использовать в селекторах.

Пример с Tailwind:

<DropdownMenu.Item
  className="px-4 py-2 cursor-pointer data-[highlighted]:bg-blue-500 data-[highlighted]:text-white"
>
  Пункт меню
</DropdownMenu.Item>

Взаимодействие компонентов и композиция

Radix UI строится на композиции компонентов. Root + Trigger + Content можно комбинировать:

  • Использовать один Content для нескольких Trigger.
  • Встраивать Nested Menus, Tooltips и Popovers.
  • Передавать кастомные элементы через asChild для полной интеграции с дизайном.

Такой подход делает библиотеку гибкой, масштабируемой и полностью совместимой с React-экосистемой.