Radix UI — это библиотека компонентов с низким уровнем стилизации,
предназначенная для создания высококачественных интерфейсов в React.
Основные строительные блоки, такие как Root,
Trigger, Portal и Content,
обеспечивают гибкую работу с интерактивными элементами, такими как
модальные окна, тултипы, выпадающие меню и аккордеоны. Рассмотрим каждый
из них подробно.
Компонент Root является корневым контейнером для всех
остальных компонентов определенного интерактивного элемента. Он
управляет внутренним состоянием, обеспечивает контекст для дочерних
компонентов и является обязательным для корректной работы системы.
Ключевые свойства Root:
defaultOpen — задает начальное состояние видимости
элемента (true/false).open — управляемое состояние, позволяет полностью
контролировать открытие и закрытие.onOpenChange — функция обратного вызова, вызываемая при
изменении состояния, полезна для синхронизации с внешним
состоянием.modal — логическое значение, которое делает компонент
модальным (важно для всплывающих окон и диалогов).Пример использования Root для диалогового окна:
import * as Dialog from '@radix-ui/react-dialog';
<Dialog.Root defaultOpen={false}>
<Dialog.Trigger>Открыть диалог</Dialog.Trigger>
<Dialog.Content>
<p>Содержимое диалога</p>
</Dialog.Content>
</Dialog.Root>
Root автоматически управляет фокусом и поведением клавиатуры, обеспечивая доступность компонентов.
Trigger — это элемент, который запускает открытие или
закрытие интерактивного компонента. Он работает только внутри
Root и наследует контекст управления состоянием.
Особенности Trigger:
<button>.asChild, позволяющее обернуть
кастомный компонент, сохраняя семантику и стили.Пример использования Trigger:
<Dialog.Root>
<Dialog.Trigger asChild>
<button className="trigger-button">Открыть диалог</button>
</Dialog.Trigger>
<Dialog.Content>
<p>Содержимое диалога</p>
</Dialog.Content>
</Dialog.Root>
Использование asChild позволяет полностью контролировать
внешний вид триггера, не теряя функциональности Radix UI.
Portal отвечает за рендеринг содержимого компонента в
отдельный узел DOM, обычно в конце <body>. Это
необходимо для правильного позиционирования всплывающих элементов и
предотвращения перекрытия другими элементами страницы.
Преимущества Portal:
Пример использования Portal с Content:
<Dialog.Root>
<Dialog.Trigger>Открыть диалог</Dialog.Trigger>
<Dialog.Portal>
<Dialog.Content className="dialog-content">
<p>Содержимое, рендерится через портал</p>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
Без использования Portal компонент может быть ограничен контекстом родительских стилей, что иногда нарушает визуальное отображение.
Content — это компонент, который отображает саму область
интерактивного элемента, например, модального окна, всплывающего меню
или тултипа. Он тесно интегрирован с Root, получая
состояние видимости и управление фокусом.
Основные возможности Content:
className,
оставляя полную свободу кастомизации.Portal для корректного
отображения.Пример Content с анимацией:
<Dialog.Root>
<Dialog.Trigger>Открыть диалог</Dialog.Trigger>
<Dialog.Portal>
<Dialog.Content className="dialog-content animate-fade-in">
<p>Модальное содержимое с анимацией</p>
<Dialog.Close>Закрыть</Dialog.Close>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
Content управляет закрытием через внутренние события, такие как
нажатие кнопки Close, Esc или клики за пределами окна.
Схема взаимодействия Root, Trigger, Portal и Content выглядит следующим образом:
Root создаёт контекст и управляет состоянием
открытия.Trigger инициирует изменение состояния Root.Portal обеспечивает рендеринг Content в отдельный узел
DOM.Content отображает основной контент и управляет
фокусом, закрытием и анимациями.Такой подход позволяет создавать доступные, гибкие и настраиваемые интерфейсы с минимальной зависимостью от внешних библиотек для управления состоянием или позиционированием.
Хотите, я следующим шагом покажу подробный разбор всех событий и хуков, которые можно использовать вместе с Root, Trigger, Portal и Content для сложных интерфейсов?