В основе работы Floating UI лежит концепция цепочек
обработчиков (middleware chain), которые
последовательно модифицируют позиционирование всплывающих элементов.
Цепочка позволяет гибко управлять смещением (offset),
адаптацией под границы видимой области (flip,
shift) и другими аспектами поведения всплывающих
элементов.
Каждый обработчик в цепочке получает объект с текущим состоянием позиции, выполняет необходимые вычисления и возвращает объект с обновлёнными координатами. Этот подход обеспечивает высокую модульность и возможность добавления собственных обработчиков.
import { computePosition, offset, flip, shift } from '@floating-ui/dom';
computePosition(reference, floating, {
middleware: [
offset(10),
flip(),
shift({ padding: 5 })
]
}).then(({ x, y }) => {
Object.assign(floating.style, {
left: `${x}px`,
top: `${y}px`
});
});
Цепочка выполняется строго последовательно.
Результат каждого обработчика передаётся следующему. Это позволяет,
например, сначала сместить элемент на фиксированное расстояние
(offset), затем проверить доступное пространство и при
необходимости перевернуть позицию (flip), а после —
скорректировать положение внутри границ контейнера
(shift).
Каждый из этих обработчиков возвращает объект с ключами
x, y, а также дополнительной информацией
(middlewareData), которую можно использовать в последующих
обработчиках.
Floating UI позволяет создавать пользовательские middleware для специфических задач. Обработчик — это функция, принимающая объект с текущим положением и возвращающая объект с модифицированными координатами.
Пример создания кастомного смещения по кривой:
function curveOffset(value) {
return ({ x, y }) => {
return {
x: x + Math.sin(y / 50) * value,
y: y + Math.cos(x / 50) * value
};
};
}
computePosition(reference, floating, {
middleware: [curveOffset(15)]
});
Каждый обработчик может сохранять данные в
middlewareData. Это позволяет передавать промежуточные
значения другим обработчикам или использовать их для визуальных
эффектов:
function logPosition() {
return ({ x, y, middlewareData }) => {
console.log('Текущая позиция:', x, y);
return { x, y, middlewareData };
};
}
Применение middlewareData особенно полезно при
комбинировании стандартных обработчиков с кастомными для сложных
интерфейсов, например, при динамическом размещении подсказок с
анимацией.
Middleware может быть асинхронным, возвращая промис с координатами. Это открывает возможности для интеграции с внешними API, например, для получения размеров динамически загружаемого контента.
function asyncOffset() {
return async ({ x, y }) => {
const extraOffset = await fetchOffsetFromServer();
return { x: x + extraOffset, y };
};
}
Цепочка корректно обработает промисы и передаст результат следующему middleware, сохраняя последовательность вычислений.
Для создания сложных интерфейсов Floating UI предлагает комбинировать стандартные middleware с пользовательскими, создавая полноценные цепочки обработки:
computePosition(reference, floating, {
middleware: [
offset(5),
flip(),
shift({ padding: 8 }),
curveOffset(10),
logPosition()
]
});
В этом примере координаты элемента последовательно модифицируются пятью обработчиками, каждый из которых вносит свой вклад в итоговое положение.
offset первым — чтобы смещения
применялись до проверки границ.flip и shift ставить
после смещения для корректной адаптации к контейнеру.Цепочка обработки Floating UI — это мощный инструмент, который делает позиционирование всплывающих элементов гибким, предсказуемым и легко настраиваемым. Правильное проектирование middleware позволяет управлять поведением подсказок, меню и тултипов даже в самых сложных интерфейсах.