Popover

Плавающий контейнер со стрелкой-указателем, открывающийся рядом с элементом-триггером. Используется для дополнительных действий, форм, подсказок и вложенных меню. Позиционирование — через @cloud-ru/ds-popover-private (Floating UI), со стрелкой и auto-flip при нехватке места.

Когда использовать

  • Выпадающий блок действий над таблицей или карточкой.
  • Inline-форма («Переименовать», «Добавить метку»).
  • Контекстная подсказка, которой мало пространства Tooltip’а.

Когда не нужен: модальный диалог (берите Modal), статичная подсказка с коротким текстом (берите Tooltip), выпадающее меню выбора (берите Select/DropdownMenu).

Анатомия

Placement

12 вариантов — базовая сторона (top|right|bottom|left) × выравнивание (-start по началу триггера, -end по концу, без суффикса — по центру). При нехватке места автоматически подменяется fallback из DEFAULT_FALLBACK_PLACEMENTS.

Trigger

Источник открытия: click (дефолт), hover, focus / focusVisible, композиты hoverAndFocus, hoverAndFocusVisible, clickAndFocusVisible — для контролов, открываемых и мышью, и с клавиатуры.

Popover width strategy

Ширина поповера относительно триггера: auto — по контенту; gte — не меньше триггера; eq — ровно как триггер.

Popover height strategy

Высота поповера относительно доступного пространства: auto — по контенту; lte — не больше доступного; eq — точно по доступному.

Установка

pnpm add @cloud-ru/ds-popover
import { Popover, PLACEMENT, TRIGGER } from '@cloud-ru/ds-popover'

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

Базовый Popover

Базовый PopoverКлик-триггер, placement=top.
tsx
import { Popover } from '@cloud-ru/ds-popover';

export function Basic() {
  return (
    <Popover content='Подсказка для пользователя' placement='top' trigger='click'>
      <button type='button'>Открыть поповер</button>
    </Popover>
  );
}

Триггер по наведению

Триггер по наведениюtrigger="hover" — подходит для информационных карточек.
tsx
import { Popover } from '@cloud-ru/ds-popover';

export function HoverTrigger() {
  return (
    <Popover content='Открывается при наведении' trigger='hover' placement='top'>
      <button type='button'>Наведи курсор</button>
    </Popover>
  );
}

Placement bottom-end

Placement bottom-endВыравнивание поповера по правому краю триггера.
tsx
import { Popover } from '@cloud-ru/ds-popover';

export function Placement() {
  return (
    <Popover content='Снизу справа' placement='bottom-end' trigger='click'>
      <button type='button'>bottom-end</button>
    </Popover>
  );
}

Props

Types

PropsPopoverProps
PropTypeDefaultRequiredDescription
childrenReactNode | ChildrenFunctionnoТриггер поповера (подробнее читайте ниже)
classNamestringno
closeOnEscapeKeybooleantruenoЗакрывать ли по нажатию на кнопку `Esc`
closeOnPopstatebooleannoЗакрывать ли поповер при переходе по истории браузера
containerRefObject<HTMLElement | null>noКонтейнер портала (ref). Переопределяет `PortalContext` для этого инстанса — по аналогии с `container` у Modal/Drawer. По умолчанию берётся из `PortalContextProvider`.
contentReactNodeyesКонтент поповера (отображается внутри контейнера по макету)
data-test-idstringno
disableSpanWrapperbooleannoОтключает для `isValidElement` внешнюю обертку триггера <br/> Пригодится для элементов с `position: absolute` <br/> Работает для триггеров, которые умеют отдать свою DOM-ноду: нативные элементы, `forwardRef`-компоненты и компоненты, помеченные `withInnerRefSupport` из `@cloud-ru/ds-utils`. Остальные всё равно получают `<span>` — без ноды поповеру не от чего считать позицию; в dev-режиме об этом печатается предупреждение.
fallbackPlacementsPlacement[]noЦепочка расположений которая будет применяться к поповеру от первого к последнему если при текущем он не влезает.
heightStrategy"auto" | "eq" | "lte"autonoСтратегия управления высотой контейнера поповера <br/> - `auto` - соответствует высоте контента, <br/> - `lte` - Less Than or Equal, равен высоте таргета или меньше ее, если контент в поповере меньше, <br/> - `eq` - Equal, строго равен высоте таргета.
hoverDelayClosenumbernoЗадержка закрытия по ховеру
hoverDelayOpennumbernoЗадержка открытия по ховеру
offsetnumber0noОтступ поповера от его триггер-элемента (в пикселях).
onOpenChange((isOpen: boolean) => void)noКолбек отображения компонента. Срабатывает при изменении состояния open.
openbooleannoУправляет состоянием показан/не показан.
outsideClickboolean | OutsideClickHandlernoЗакрывать ли при клике вне поповера
placement"bottom" | "bottom-end" | "bottom-start" | "left" | "left-end" | "left-start" | "right" | "right-end" | "right-start" | "top" | "top-end" | "top-start"topnoПоложение поповера относительно своего триггера (children).
stopPropagationStopPropagationHandlers{ onClick: true, onMouseDown: true, onMouseUp: true, onTouchStart: true, onTouchEnd: true, onTouchMove: true }noГасить всплытие pointer/touch-событий с floating-контейнера (`stopPropagation`). По умолчанию все хендлеры включены. Для drag&drop внутри поповера отключите `onMouseUp` / `onTouchEnd`, чтобы они дошли до `document`.
trigger"click" | "clickAndFocusVisible" | "focus" | "focusVisible" | "hover" | "hoverAndFocus" | "hoverAndFocusVisible"clicknoУсловие отображения поповера: <br/> - `click` - открывать по клику <br/> - `hover` - открывать по ховеру <br/> - `focusVisible` - открывать по focus-visible <br/> - `focus` - открывать по фокусу <br/> - `hoverAndFocusVisible` - открывать по ховеру и focus-visible <br/> - `hoverAndFocus` - открывать по ховеру и фокусу <br/> - `clickAndFocusVisible` - открывать по клику и focus-visible
triggerClassNamestringnoCSS-класс триггера
triggerClickByKeysbooleantruenoВызывается ли попоповер по нажатию клавиш Enter/Space (при trigger = `click`)
triggerRefForwardedRef<HTMLElement | ReferenceType | null>noRef ссылка на триггер
widthStrategy"auto" | "eq" | "gte"autonoСтратегия управления шириной контейнера поповера <br/> - `auto` - соответствует ширине контента, <br/> - `gte` - Great Than or Equal, равен ширине таргета или больше ее, если контент в поповере шире, <br/> - `eq` - Equal, строго равен ширине таргета.

Types

PopoverProps

Storybook

Figma