Floating UI — это библиотека для динамического позиционирования элементов интерфейса, таких как всплывающие подсказки (tooltips), выпадающие меню (dropdowns) и модальные окна. Одной из ключевых возможностей является управление положением стрелки (arrow), которая визуально указывает на элемент-триггер. Стрелка не просто декоративный элемент: её точное позиционирование требует учёта множества факторов, включая размеры контейнера, границы окна и возможные смещения.
Arrow — это отдельный элемент DOM, который следует за плавающим элементом (floating element) и указывает на целевой элемент (reference element). Floating UI обеспечивает автоматическое вычисление позиции стрелки с учётом:
top, bottom, left,
right)Для работы с стрелкой в Floating UI используется модуль
arrow, который подключается через middleware при
создании позиции:
import { computePosition, offset, flip, shift, arrow } from '@floating-ui/dom';
const reference = document.querySelector('#button');
const floating = document.querySelector('#tooltip');
const arrowElement = document.querySelector('#arrow');
computePosition(reference, floating, {
placement: 'top',
middleware: [
offset(8),
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` : ''
});
});
Ключевые моменты:
offset(8) задаёт расстояние между плавающим элементом и
reference element.flip() позволяет менять сторону, если изначальная
позиция не помещается на экране.shift({ padding: 5 }) сдвигает элемент, чтобы он не
выходил за границы viewport.arrow({ element: arrowElement }) сообщает Floating UI,
что необходимо учитывать стрелку при расчёте позиции.arrowMiddleware arrow возвращает объект
middlewareData.arrow с координатами x и
y, которые указывают на центр стрелки
относительно плавающего элемента.
Пример структуры:
{
"arrow": {
"x": 50,
"y": 0
}
}
top),
y всегда равен 0, а x указывает горизонтальное
смещение стрелки.left), x = 0, а
y задаёт вертикальное смещение.Размер стрелки задаётся через CSS. Floating UI рекомендует использовать переменные для динамических вычислений:
#arrow {
width: 12px;
height: 12px;
background: black;
clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
position: absolute;
}
clip-path создаёт треугольник.position: absolute необходим для точного
позиционирования.x и y.Стрелка часто используется вместе с
offset, flip
и shift, чтобы обеспечить корректное
позиционирование в любых условиях:
offset() увеличивает
или уменьшает расстояние между плавающим элементом и reference
element.flip()
помогает стрелке оставаться видимой при переполнении viewport.shift() не
позволяет стрелке выходить за пределы окна и предотвращает её
обрезание.Иногда требуется, чтобы стрелка находилась не по центру, а смещалась к углу:
arrow({
element: arrowElement,
padding: 10 // Минимальное расстояние от края
})
padding задаёт отступ стрелки от границ плавающего
элемента.Если размеры reference element изменяются (например, кнопка растёт
при hover), стрелка автоматически перестраивается при каждом вызове
computePosition. Это позволяет создавать адаптивные тултипы
без ручного пересчёта координат.
arrow.padding.offset, flip
и shift для предотвращения наложений и переполнения.Строгое соблюдение этих принципов позволяет создавать гибкие и адаптивные интерфейсы, где стрелка всегда указывает на целевой элемент, оставаясь видимой и аккуратно встроенной в дизайн.