Root, Trigger, Content

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

Наиболее фундаментальные элементы практически всех компонентов Radix UI:

  • Root
  • Trigger
  • Content

Эти элементы формируют основу интерактивных интерфейсных паттернов: выпадающих меню, попапов, диалоговых окон, тултипов, аккордеонов, контекстных меню и других сложных UI-структур.


Root

Назначение

Root представляет корневой контейнер компонента.

Он выполняет несколько ключевых функций:

  • хранит состояние компонента
  • управляет контекстом для дочерних элементов
  • координирует взаимодействие между Trigger и Content
  • отвечает за поведенческую логику

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


Базовая структура

Типичная структура компонента Radix UI выглядит следующим образом:

import * as Dialog from "@radix-ui/react-dialog";

<Dialog.Root>
  <Dialog.Trigger />
  <Dialog.Content />
</Dialog.Root>

Здесь:

  • Root управляет состоянием
  • Trigger инициирует действие
  • Content отображает интерфейс

Управление состоянием

Root может работать в двух режимах:

1. Неконтролируемый режим

Состояние управляется самим компонентом.

<Dialog.Root>

В этом режиме библиотека самостоятельно отслеживает:

  • открытие
  • закрытие
  • фокус
  • взаимодействия пользователя

2. Контролируемый режим

Состояние управляется извне через React.

const [open, setOpen] = useState(false);

<Dialog.Root open={open} onOpenCha nge={setOpen}>

Основные свойства:

Свойство Назначение
open текущее состояние
defaultOpen начальное состояние
onOpenChange обработчик изменения

Такой подход позволяет интегрировать компонент в сложные состояния приложения.


Контекст

Root создаёт React Context, который используется дочерними элементами:

  • Trigger
  • Content
  • Overlay
  • Portal
  • другие внутренние части

Через этот контекст передаются:

  • состояние открытия
  • функции управления
  • информация о фокусе
  • параметры позиционирования

Это позволяет дочерним элементам взаимодействовать без прямой передачи props.


Управление фокусом

Root также отвечает за контроль фокуса, включая:

  • сохранение предыдущего фокуса
  • перенос фокуса в Content
  • возврат фокуса к Trigger
  • предотвращение утечки фокуса

Такая логика необходима для соблюдения стандартов доступности (ARIA).


Пример с Popover

import * as Popover from "@radix-ui/react-popover";

<Popover.Root>
  <Popover.Trigger>Open</Popover.Trigger>
  <Popover.Content>
    Popover content
  </Popover.Content>
</Popover.Root>

Popover.Root управляет:

  • открытием
  • позиционированием
  • закрытием при клике вне компонента
  • фокусом

Trigger

Назначение

Trigger — элемент, который инициирует действие компонента.

Он отвечает за:

  • открытие интерфейса
  • переключение состояния
  • взаимодействие пользователя

В большинстве компонентов Trigger — это кнопка или интерактивный элемент.


Пример

<Popover.Trigger>
  Open popover
</Popover.Trigger>

При взаимодействии пользователя происходит изменение состояния Root.


Автоматическая логика

Trigger автоматически подключён к Root через контекст.

Поэтому без дополнительного кода реализуются:

  • обработка кликов
  • управление состоянием
  • синхронизация фокуса
  • клавиатурная навигация

Поддержка клавиатуры

Radix UI автоматически реализует стандартные клавиатурные взаимодействия:

Клавиша Поведение
Enter активация
Space активация
Esc закрытие
Tab навигация

Эти механизмы встроены в Trigger.


Использование собственного элемента

По умолчанию Trigger рендерит button.

Однако часто требуется использовать кастомный элемент.

Для этого используется asChild.

<Popover.Trigger asChild>
  <button className="custom-button">
    Open
  </button>
</Popover.Trigger>

В этом случае:

  • Radix не создаёт дополнительный DOM-узел
  • поведение передаётся дочернему элементу

Преимущества asChild

  • сохранение семантики HTML
  • интеграция с существующими компонентами
  • отсутствие лишних обёрток

Это одна из ключевых архитектурных особенностей Radix UI.


Несколько триггеров

Некоторые компоненты допускают несколько Trigger.

Пример:

<Dialog.Root>
  <Dialog.Trigger>Open dialog</Dialog.Trigger>
  <Dialog.Trigger>Open again</Dialog.Trigger>
</Dialog.Root>

Все триггеры управляют одним состоянием Root.


Атрибуты доступности

Trigger автоматически получает ARIA-атрибуты:

  • aria-expanded
  • aria-controls
  • data-state

Пример DOM:

<button aria-expanded="true" data-state="open">

Эти атрибуты используются:

  • скринридерами
  • CSS-стилизацией
  • тестированием

Content

Назначение

Content представляет основное содержимое компонента, которое отображается после активации Trigger.

Примеры:

Компонент Content
Dialog окно диалога
Popover всплывающая панель
Dropdown Menu список действий
Tooltip подсказка

Базовый пример

<Dialog.Content>
  Dialog content
</Dialog.Content>

Этот элемент содержит всю пользовательскую разметку интерфейса.


Порталы

Во многих компонентах Content рендерится через React Portal.

Это позволяет:

  • избежать проблем со z-index
  • выводить элемент вне DOM-иерархии
  • управлять позиционированием

Пример:

<Dialog.Portal>
  <Dialog.Content>
    Dialog content
  </Dialog.Content>
</Dialog.Portal>

Управление фокусом

Когда Content открывается, Radix автоматически:

  1. переносит фокус внутрь компонента
  2. блокирует фокус вне компонента
  3. восстанавливает фокус после закрытия

Это критично для:

  • accessibility
  • корректной навигации
  • модальных интерфейсов

Закрытие при клике вне

Content отслеживает события:

  • pointerdown
  • focusoutside
  • escape key

Например:

<Popover.Content>
  Popover
</Popover.Content>

Клик вне области автоматически закрывает поповер.


Позиционирование

Для компонентов вроде Popover и Tooltip используется динамическое позиционирование.

Свойства:

Свойство Назначение
side сторона отображения
align выравнивание
sideOffset отступ

Пример:

<Popover.Content
  side="bottom"
  align="start"
  sideOffset={8}
>

Анимации

Radix UI предоставляет data-атрибуты для CSS-анимаций.

Пример:

[data-state="open"] {
  animation: fadeIn 150ms;
}

[data-state="closed"] {
  animation: fadeOut 150ms;
}

Также доступны атрибуты:

Атрибут Значение
data-state open / closed
data-side top / bottom / left / right

Это позволяет легко создавать адаптивные анимации.


Взаимодействие с Overlay

Во многих компонентах Content используется вместе с Overlay.

Пример диалога:

<Dialog.Portal>
  <Dialog.Overlay />
  <Dialog.Content>
    Dialog
  </Dialog.Content>
</Dialog.Portal>

Overlay создаёт затемнённый фон, а Content отображает окно.


Закрытие изнутри

Внутри Content часто используются элементы закрытия:

<Dialog.Close>Close</Dialog.Close>

Это позволяет управлять состоянием Root изнутри компонента.


Стилизация Content

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

Пример:

.popoverContent {
  background: white;
  border-radius: 6px;
  padding: 20px;
  box-shadow: 0 10px 25px rgba(0,0,0,0.2);
}

Использование:

<Popover.Content className="popoverContent">

Связь Root, Trigger и Content

Взаимодействие элементов можно представить следующим образом:

Root
 ├── Trigger
 └── Content

Процесс работы:

  1. Пользователь взаимодействует с Trigger
  2. Trigger вызывает изменение состояния в Root
  3. Root обновляет контекст
  4. Content отображается или скрывается

Поток событий

User action
     ↓
Trigger
     ↓
Root state change
     ↓
Content render

Эта архитектура обеспечивает:

  • разделение ответственности
  • переиспользуемость
  • гибкость интерфейса

Пример полной структуры Popover

import * as Popover from "@radix-ui/react-popover";

function Example() {
  return (
    <Popover.Root>

      <Popover.Trigger>
        Open
      </Popover.Trigger>

      <Popover.Portal>

        <Popover.Content side="bottom">
          Content

          <Popover.Close>
            Close
          </Popover.Close>

        </Popover.Content>

      </Popover.Portal>

    </Popover.Root>
  );
}

Ключевые архитектурные принципы

1. Композиция

Компоненты собираются из независимых примитивов.


2. Контекстное управление

Root передаёт состояние через React Context.


3. Headless-подход

Radix предоставляет поведение, а не стили.


4. Доступность

ARIA-атрибуты, управление фокусом и клавиатурная навигация реализованы автоматически.


Итоговая роль элементов

Элемент Роль
Root управление состоянием
Trigger инициирование действия
Content отображение интерфейса

Эти три примитива образуют основной архитектурный паттерн Radix UI, который повторяется практически во всех компонентах библиотеки.