FloatingPortal — это компонент из библиотеки
Floating UI, который служит для рендеринга всплывающих элементов вне
обычного DOM-контекста родителя. Это особенно важно, когда всплывающий
элемент (например, tooltip, popover, dropdown) не должен быть ограничен
стилями родительских контейнеров, такими как
overflow: hidden или z-index.
body.FloatingFocusManager,
FloatingArrow и другими утилитами Floating UI для
полноценного управления всплывающими элементами.import { FloatingPortal } from '@floating-ui/react-dom-interactions';
FloatingPortal не требует отдельной установки, если используется
основной пакет Floating UI для React
(@floating-ui/react-dom-interactions).
import { useState } from 'react';
import { FloatingPortal, useFloating } from '@floating-ui/react-dom-interactions';
function TooltipExample() {
const [open, setOpen] = useState(false);
const { x, y, reference, floating, strategy } = useFloating({
placement: 'top'
});
return (
<>
<button ref={reference} onMouseEn ter={() => setOpen(true)} onMouseLe ave={() => setOpen(false)}>
Hover me
</button>
{open && (
<FloatingPortal>
<div
ref={floating}
style={{
position: strategy,
top: y ?? 0,
left: x ?? 0,
background: 'black',
color: 'white',
padding: '5px 10px',
borderRadius: '4px'
}}
>
Tooltip content
</div>
</FloatingPortal>
)}
</>
);
}
Ключевые моменты:
<FloatingPortal>
вместо обычного родителя.strategy управляет типом позиционирования:
absolute или fixed.x и y — вычисленные координаты,
определяемые Floating UI.FloatingPortal поддерживает множественные всплывающие элементы в одной странице. Каждый портал может быть независимым:
<FloatingPortal id="dropdown-portal">
<DropdownMenu />
</FloatingPortal>
<FloatingPortal id="tooltip-portal">
<Tooltip />
</FloatingPortal>
Параметр id позволяет явно управлять конкретным порталом
и предотвращает конфликт с другими порталами на странице.
По умолчанию FloatingPortal рендерит свои элементы в
document.body. При необходимости можно указать кастомный
контейнер:
<FloatingPortal root={document.getElementById('custom-root')}>
<PopoverContent />
</FloatingPortal>
FloatingPortal полностью совместим с библиотеками анимации (например, Framer Motion). Основное правило — анимировать дочерние элементы портала, а не сам портал. Пример:
import { motion } from 'framer-motion';
<FloatingPortal>
<motion.div
ref={floating}
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.95 }}
style={{ position: strategy, top: y ?? 0, left: x ?? 0 }}
>
Animated Popover
</motion.div>
</FloatingPortal>
id
или root для управления несколькими порталами.FloatingFocusManager для контроля фокуса и клавиатурной
навигации.Popover с стрелкой и фокусом:
import { FloatingPortal, useFloating, FloatingArrow, FloatingFocusManager } from '@floating-ui/react-dom-interactions';
<FloatingFocusManager context={context}>
<FloatingPortal>
<div ref={floating} style={{ position: strategy, top: y ?? 0, left: x ?? 0 }}>
Popover Content
<FloatingArrow ref={arrowRef} />
</div>
</FloatingPortal>
</FloatingFocusManager>
FloatingFocusManager обеспечивает правильное управление
фокусом при открытии и закрытии портала.FloatingArrow позволяет визуально указать на
элемент-источник.FloatingPortal в Floating UI — это надежный инструмент для управления всплывающими элементами вне обычного DOM-контекста, обеспечивающий гибкость позиционирования, совместимость с анимацией и удобное управление несколькими порталами на одной странице.