Root, Menu, Trigger

Radix UI предоставляет низкоуровневые, доступные и полностью управляемые компоненты пользовательского интерфейса. Среди них Root, Menu и Trigger являются ключевыми элементами для построения интерактивных меню и всплывающих элементов управления. Они обеспечивают правильное управление состоянием, фокусом и доступностью, позволяя создавать сложные интерфейсы без потери контроля над поведением.


Root

Root — это основной контейнер для компонентов Radix UI, таких как Menu, Dialog или Popover. Он служит точкой управления состоянием и контекстом для дочерних компонентов.

Особенности:

  • Контекст состояния: Root предоставляет контекст, который управляет открытием, закрытием и взаимодействием дочерних элементов.
  • Управляемое и неуправляемое состояние: состояние open может контролироваться внешне через пропсы или управляться внутренне автоматически.
  • Обработчики событий: Root обеспечивает корректную работу клавиатурных и мышиных событий для вложенных компонентов.

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

import * as Menu from '@radix-ui/react-menu';

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

Здесь Menu.Root выступает как контейнер всего меню. Все дочерние компоненты получают доступ к состоянию open и могут реагировать на события взаимодействия пользователя.


Menu — это основное содержимое меню, которое может включать интерактивные элементы, подменю и разделители. В Radix UI Menu разделен на несколько компонентов:

  1. Menu.Content — контейнер с визуальным отображением меню.
  2. Menu.Item — отдельный интерактивный пункт меню.
  3. Menu.Label — заголовок группы элементов.
  4. Menu.Separator — горизонтальная линия для разделения элементов.
  5. Menu.Group — логическая группа элементов внутри меню.

Ключевые моменты:

  • Menu.Content автоматически позиционируется относительно Trigger с использованием механизма портала.
  • Встроенная поддержка клавиатуры: стрелки для навигации между элементами, Enter и Space для выбора.
  • Полная доступность: элементы меню корректно работают с экранными читалками.

Пример вложенного меню с разделителями и группами:

<Menu.Root>
  <Menu.Trigger>Меню действий</Menu.Trigger>
  <Menu.Content sideOffset={5}>
    <Menu.Group>
      <Menu.Item>Редактировать</Menu.Item>
      <Menu.Item>Копировать</Menu.Item>
    </Menu.Group>
    <Menu.Separator />
    <Menu.Group>
      <Menu.Item>Удалить</Menu.Item>
    </Menu.Group>
  </Menu.Content>
</Menu.Root>

sideOffset позволяет задать отступ меню от триггера, обеспечивая точное позиционирование.


Trigger

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

Особенности:

  • Автоматическое управление открытием: при клике или фокусе на триггере меню открывается.
  • Атрибуты доступности: aria-haspopup, aria-expanded и aria-controls генерируются автоматически.
  • Произвольный контент: внутри Trigger может находиться текст, иконки или другие элементы, обеспечивая гибкий дизайн.

Пример использования Trigger с кастомной кнопкой:

<Menu.Root>
  <Menu.Trigger asChild>
    <button className="custom-button">
      Опции
    </button>
  </Menu.Trigger>
  <Menu.Content>
    <Menu.Item>Сохранить</Menu.Item>
    <Menu.Item>Загрузить</Menu.Item>
  </Menu.Content>
</Menu.Root>

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


Взаимодействие Root, Menu и Trigger

  1. Root управляет состоянием: открытие/закрытие меню, обработка фокуса и клавиатурной навигации.
  2. Trigger инициирует действия: клики или фокус на триггере изменяют состояние Root.
  3. Menu отображает содержимое: реагирует на состояние Root, автоматически управляет фокусом и доступностью.

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


Рекомендации по использованию

  • Для сложных меню с подменю рекомендуется использовать Menu.Sub и отдельные Menu.Content для вложенных уровней.
  • Всегда использовать asChild для кастомных кнопок, чтобы сохранить доступность.
  • Управление состоянием через open и onOpenChange позволяет интегрировать меню с глобальным состоянием приложения, например Redux или Zustand.
  • Использовать sideOffset и align для точного позиционирования меню относительно триггера, особенно в адаптивной верстке.

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