Floating UI — это библиотека для управления позиционированием всплывающих элементов на веб-странице. Она предоставляет низкоуровневые инструменты для точного расчета координат, позиционирования, управления смещением и взаимодействия с окружающим контентом. Ключевое преимущество библиотеки — гибкость и контроль над поведением всплывающих элементов, таких как тултипы, поповеры и дропдауны.
Базовая структура работы с Floating UI включает следующие компоненты: reference element (элемент, относительно которого позиционируется всплывающее окно), floating element (сам всплывающий элемент), middleware (промежуточные функции для модификации позиции), и placement (направление отображения: top, bottom, left, right, auto).
Для расчета позиции используется функция
computePosition:
import { computePosition, offset, flip, shift } from '@floating-ui/dom';
const reference = document.querySelector('#button');
const floating = document.querySelector('#tooltip');
computePosition(reference, floating, {
placement: 'top',
middleware: [
offset(10),
flip(),
shift({ padding: 5 })
]
}).then(({ x, y }) => {
Object.assign(floating.style, {
left: `${x}px`,
top: `${y}px`
});
});
Ключевые моменты:
placement определяет предпочтительное направление
появления всплывающего окна.offset добавляет смещение от reference element.flip автоматически меняет позицию, если основной
вариант не помещается.shift корректирует координаты, чтобы элемент не выходил
за границы viewport.Middleware — это функции, которые можно использовать для модификации позиции. Среди наиболее популярных:
Пример использования стрелки:
import { arrow } from '@floating-ui/dom';
const arrowElement = document.querySelector('#arrow');
computePosition(reference, floating, {
placement: 'bottom',
middleware: [
offset(10),
flip(),
shift({ padding: 5 }),
arrow({ element: arrowElement })
]
}).then(({ x, y, middlewareData }) => {
Object.assign(floating.style, {
left: `${x}px`,
top: `${y}px`
});
const { x: arrowX, y: arrowY } = middlewareData.arrow;
Object.assign(arrowElement.style, {
left: arrowX != null ? `${arrowX}px` : '',
top: arrowY != null ? `${arrowY}px` : ''
});
});
Для элементов, которые могут изменять размер или перемещаться, используется autoUpdate. Она обеспечивает пересчет позиции при скролле, изменении размера окна или изменения размера reference/floating элемента:
import { autoUpdate } from '@floating-ui/dom';
const cleanup = autoUpdate(reference, floating, () => {
computePosition(reference, floating, {
placement: 'top',
middleware: [offset(10), flip(), shift({ padding: 5 })]
}).then(({ x, y }) => {
Object.assign(floating.style, { left: `${x}px`, top: `${y}px` });
});
});
// Для остановки наблюдения
cleanup();
Floating UI поддерживает вложенные всплывающие элементы, где позиция одного floating зависит от другого. Для этого используется цепочка middleware и расчеты с учетом всех reference элементов. Важно учитывать контекст позиционирования и ограничения контейнера.
Пример: меню с вложенными подменю:
const parentMenu = document.querySelector('#menu');
const childMenu = document.querySelector('#submenu');
computePosition(parentMenu, childMenu, {
placement: 'right-start',
middleware: [offset(5), flip(), shift({ padding: 5 })]
}).then(({ x, y }) => {
Object.assign(childMenu.style, { left: `${x}px`, top: `${y}px` });
});
offset для визуальной гармонии между
reference и floating элементом.flip и shift для адаптивного
поведения на мобильных устройствах.autoUpdate только для
активно видимых элементов.arrow с shift для корректного
позиционирования стрелок при ограниченном пространстве.Floating UI позволяет подписываться на изменения позиции через middleware, создавая кастомные обработчики. Это полезно для анимаций, динамических стилей или интеграции с библиотеками анимации:
import { computePosition, autoUpdate } from '@floating-ui/dom';
autoUpdate(reference, floating, () => {
computePosition(reference, floating).then(({ x, y }) => {
floating.style.transform = `translate3d(${x}px, ${y}px, 0)`;
// Подписка на событие позиции
floating.dispatchEvent(new CustomEvent('positionChange', { detail: { x, y } }));
});
});
Использование событий позволяет внешним компонентам реагировать на изменения позиции, создавать сложные взаимодействия, управлять анимацией появления, синхронизировать состояние с другими интерфейсными элементами.
Если нужно, я могу расширить статью отдельным разделом подробного управления подписками и кастомного middleware, с примерами отслеживания и реактивного обновления позиции в реальном времени. Это будет полноценная учебная глава для практического применения.
Хотите, чтобы я это сделал?