Portal, Content, Viewport

Radix UI предоставляет низкоуровневые, полностью управляемые компоненты для построения пользовательских интерфейсов с высокой доступностью и гибкостью. Одними из ключевых строительных блоков при создании всплывающих интерфейсов (popovers, tooltips, dropdowns и модальных окон) являются компоненты Portal, Content и Viewport. Они позволяют отделить визуальное отображение от логики компонента и управлять рендерингом в DOM с высокой точностью.


Portal

Компонент Portal используется для рендеринга дочерних элементов вне обычной иерархии DOM, где находится родительский компонент. Это особенно важно для модальных окон, тултипов и поповер-меню, чтобы избежать влияния стилей родительских контейнеров, таких как overflow: hidden или z-index.

import * as Portal from '@radix-ui/react-portal';

<Portal.Root>
  <div style={{ position: 'absolute', top: 0, left: 0 }}>
    Контент в портале
  </div>
</Portal.Root>

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

  • Изоляция DOM-контента для корректного позиционирования.
  • Снижение вероятности конфликтов со стилями родительских элементов.
  • Позволяет компонентам быть «плавающими» независимо от их родителя.

Radix UI также позволяет создавать несколько порталов с разными контейнерами через Portal.Root container={...}. Это полезно, если необходимо рендерить компоненты в разных местах DOM, например, для модальных окон и глобальных уведомлений.


Content

Компонент Content отвечает за визуальное отображение всплывающего интерфейса. Он управляет позиционированием, анимацией и доступностью. Обычно используется вместе с Popover, Tooltip или Dropdown.

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

<Popover.Root>
  <Popover.Trigger>Открыть поповер</Popover.Trigger>
  <Popover.Content side="bottom" align="center">
    Это содержимое поповера
  </Popover.Content>
</Popover.Root>

Ключевые свойства Content:

  • side: определяет, с какой стороны триггера отображается контент (top, right, bottom, left).
  • align: управляет выравниванием контента относительно триггера (start, center, end).
  • sideOffset: задает отступ от триггера, влияя на расстояние между ним и всплывающим окном.
  • collisionPadding: регулирует пространство вокруг окна для предотвращения выхода за пределы viewport.

Дополнительно: Content может быть полностью кастомизирован с анимациями, стилями и взаимодействиями с другими компонентами. Он поддерживает ключевые принципы доступности ARIA, включая role="dialog" или role="tooltip" при необходимости.


Viewport

Компонент Viewport определяет область, в пределах которой Content может располагаться. Он используется для управления видимым пространством и предотвращения выхода элементов за границы видимой области.

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

<DropdownMenu.Root>
  <DropdownMenu.Trigger>Меню</DropdownMenu.Trigger>
  <DropdownMenu.Content>
    <DropdownMenu.Viewport>
      <div>Пункт 1</div>
      <div>Пункт 2</div>
      <div>Пункт 3</div>
    </DropdownMenu.Viewport>
  </DropdownMenu.Content>
</DropdownMenu.Root>

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

  • Определяет размеры и границы для позиционирования дочернего контента.
  • Используется для расчета столкновений и автоматического смещения контента.
  • Позволяет управлять прокруткой при ограниченном пространстве.

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


Взаимодействие Portal, Content и Viewport

Эти три компонента работают в связке:

  1. Portal рендерит контент вне родительского DOM.
  2. Content задает визуальное оформление, позиционирование и доступность всплывающего элемента.
  3. Viewport ограничивает область видимости и управляет столкновениями с краями окна или контейнера.

Пример интеграции:

<Popover.Root>
  <Popover.Trigger>Открыть поповер</Popover.Trigger>
  <Portal.Root>
    <Popover.Content side="bottom" align="center">
      <Popover.Viewport>
        <div>Внутренний контент</div>
      </Popover.Viewport>
    </Popover.Content>
  </Portal.Root>
</Popover.Root>

В этом примере Portal гарантирует, что Popover будет отображаться поверх всего контента страницы, Content управляет позиционированием и выравниванием, а Viewport обеспечивает корректное размещение внутри видимой области.


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