В библиотеке Floating UI стрелка — это визуальный элемент,
указывающий на источник всплывающего элемента (popper, tooltip,
dropdown). Правильное позиционирование стрелки требует знания точных
координат относительно родительского элемента и контекста позиции.
Floating UI предоставляет утилиту arrow для вычисления этих
координат с учётом смещения и границ видимой области.
Для работы со стрелкой необходимо импортировать модуль
arrow из @floating-ui/dom или
@floating-ui/react (в зависимости от среды):
import { arrow, offset, flip, shift, computePosition } from '@floating-ui/dom';
arrow — вычисляет координаты стрелки.offset — задаёт смещение всплывающего элемента от
reference.flip — обеспечивает автоматическое изменение стороны
при нехватке места.shift — корректирует позицию, чтобы элемент не выходил
за границы viewport.computePosition — центральная функция, возвращающая
финальные координаты.Стрелка должна быть DOM-элементом внутри всплывающего блока. Обычно структура выглядит так:
<div id="tooltip">
Tooltip content
<div id="arrow" class="arrow"></div>
</div>
CSS для стрелки может использоваться следующий:
.arrow {
width: 10px;
height: 10px;
background: black;
transform: rotate(45deg);
position: absolute;
}
arrow работает через функцию
computePosition, которая возвращает объект с
координатами:
const reference = document.querySelector('#button');
const floating = document.querySelector('#tooltip');
const arrowEl = document.querySelector('#arrow');
computePosition(reference, floating, {
middleware: [
offset(8),
flip(),
shift({ padding: 5 }),
arrow({ element: arrowEl })
],
}).then(({ x, y, middlewareData }) => {
Object.assign(floating.style, {
left: `${x}px`,
top: `${y}px`
});
const { x: arrowX, y: arrowY } = middlewareData.arrow;
Object.assign(arrowEl.style, {
left: arrowX != null ? `${arrowX}px` : '',
top: arrowY != null ? `${arrowY}px` : ''
});
});
Ключевые моменты:
middlewareData.arrow содержит координаты x
и y, рассчитанные с учётом позиции reference.x
используется для сдвига стрелки, y оставляется пустым. Для
вертикальной позиции наоборот.offset задаёт расстояние между reference и всплывающим
элементом, которое учитывается при вычислении стрелки.Стрелку можно смещать относительно центра всплывающего элемента через
опцию padding:
arrow({ element: arrowEl, padding: 5 })
padding ограничивает движение стрелки, чтобы она не
пересекала края всплывающего блока.Если всплывающий элемент может менять позицию (например, при скролле или ресайзе окна), координаты стрелки следует пересчитывать:
function updatePosition() {
computePosition(reference, floating, {
middleware: [offset(8), flip(), shift({ padding: 5 }), arrow({ element: arrowEl })]
}).then(({ x, y, middlewareData }) => {
Object.assign(floating.style, { left: `${x}px`, top: `${y}px` });
const { x: arrowX, y: arrowY } = middlewareData.arrow;
Object.assign(arrowEl.style, {
left: arrowX != null ? `${arrowX}px` : '',
top: arrowY != null ? `${arrowY}px` : ''
});
});
}
window.addEventListener('resize', updatePosition);
window.addEventListener('scroll', updatePosition, true);
true в addEventListener для
scroll позволяет отслеживать прокрутку любого родителя, а
не только окна.top, bottom,
left, right) и выбранного middleware
flip.transform, координаты стрелки будут корректными,
так как Floating UI работает с bounding client rect.offset,
flip, shift и arrow даёт точное
позиционирование и предотвращает выход стрелки за пределы блока.position: relative или fixed.В результате применение Floating UI и middleware arrow
позволяет создавать всплывающие элементы с динамически корректируемой
стрелкой, полностью учитывающей положение reference, границы viewport и
пользовательские смещения.