Инструменты разработчика

Floating UI — это библиотека для создания плавающих элементов интерфейса, таких как тултипы, поповеры, дропдауны и модальные окна, с точным управлением позиционированием относительно целевых элементов. В основе работы лежит понятие reference element (элемент, относительно которого позиционируется плавающий блок) и floating element (сам плавающий блок).

Reference и Floating элементы

Reference элемент — это DOM-узел, вокруг которого строится логика позиционирования. Floating элемент может быть абсолютно позиционированным элементом, который следует за reference элементом, учитывая ограничения контейнера, viewport и другие условия.

import { computePosition } from '@floating-ui/dom';

const reference = document.querySelector('#button');
const floating = document.querySelector('#tooltip');

computePosition(reference, floating, {
  placement: 'top',
}).then(({ x, y }) => {
  Object.assign(floating.style, {
    left: `${x}px`,
    top: `${y}px`,
  });
});

Параметры позиционирования

Placement — ключевой параметр, определяющий расположение floating элемента относительно reference. В Floating UI используется формат "side-alignment":

  • top, bottom, left, right — стороны относительно reference.
  • top-start, top-end, bottom-start, bottom-end — уточненные позиции с учетом выравнивания по краям.

Middleware — цепочка функций, которые изменяют позицию плавающего элемента перед её окончательной установкой. Основные middleware:

  • offset — смещает элемент на заданное количество пикселей.
  • flip — автоматически изменяет сторону, если элемент не помещается.
  • shift — подгоняет элемент в видимую область.
  • arrow — вычисляет положение стрелки тултипа относительно reference.
  • size — управляет размерами floating элемента в зависимости от доступного пространства.

Пример использования middleware:

import { offset, flip, shift, arrow } from '@floating-ui/dom';

computePosition(reference, floating, {
  placement: 'bottom',
  middleware: [
    offset(8),
    flip(),
    shift({ padding: 5 }),
    arrow({ element: document.querySelector('#arrow') }),
  ],
}).then(({ x, y, middlewareData }) => {
  Object.assign(floating.style, {
    left: `${x}px`,
    top: `${y}px`,
  });

  const { x: arrowX, y: arrowY } = middlewareData.arrow;
  Object.assign(document.querySelector('#arrow').style, {
    left: arrowX != null ? `${arrowX}px` : '',
    top: arrowY != null ? `${arrowY}px` : '',
  });
});

Динамическое позиционирование и реактивность

Floating UI позволяет отслеживать изменения размера reference и viewport, чтобы динамически обновлять позицию floating элемента. Для этого используется метод autoUpdate:

import { autoUpdate } from '@floating-ui/dom';

const cleanup = autoUpdate(reference, floating, () => {
  computePosition(reference, floating, {
    placement: 'top',
    middleware: [offset(10), flip(), shift()],
  }).then(({ x, y }) => {
    Object.assign(floating.style, { left: `${x}px`, top: `${y}px` });
  });
});

autoUpdate автоматически реагирует на:

  • Скролл контейнера.
  • Изменение размеров окна.
  • Изменение размеров reference или floating элементов.

Возвращаемая функция cleanup позволяет остановить наблюдение.

Работа со стрелками и выравниванием

Для стрелок используется middleware arrow, которое принимает DOM-узел стрелки и вычисляет её координаты:

  • Положение стрелки вычисляется на основе смещений floating элемента.
  • Позволяет автоматически выравнивать стрелку даже при срабатывании flip и shift.
arrow({ element: arrowEl, padding: 5 });

padding задаёт минимальное расстояние стрелки от краёв floating элемента.

Ограничения и контейнеры

Middleware shift и flip учитывают ограничения контейнера или viewport. Можно задать:

  • boundary — элемент, в пределах которого элемент не должен выходить.
  • padding — минимальное расстояние от границ контейнера.
shift({ boundary: document.querySelector('#container'), padding: 10 });

Расширенные возможности

  • Virtual elements — Floating UI позволяет использовать виртуальные reference элементы, которые не существуют в DOM, например, координаты мыши или центр кастомного компонента.
  • Композиция middleware — middleware можно комбинировать в любой последовательности для точного управления поведением плавающего элемента.
  • Производительность — библиотека минимизирует перерасчёты, используя мемоизацию и оптимизированные алгоритмы вычисления позиции.
const virtualReference = {
  getBoundingClientRect: () => ({
    x: mouseX,
    y: mouseY,
    width: 0,
    height: 0,
    top: mouseY,
    bottom: mouseY,
    left: mouseX,
    right: mouseX,
  }),
};

computePosition(virtualReference, floating, {
  placement: 'right',
  middleware: [offset(5)],
});

Интеграция с React и другими фреймворками

Floating UI предоставляет обёртки для React (@floating-ui/react) и других библиотек, упрощая использование через хуки:

import { useFloating, offset, flip, shift } from '@floating-ui/react';

const { x, y, reference, floating } = useFloating({
  placement: 'bottom',
  middleware: [offset(10), flip(), shift()],
});
  • reference и floating — рефы, привязанные к DOM элементам.
  • x и y — координаты, автоматически обновляемые при изменениях размеров и скролла.

Эта архитектура позволяет строить полностью реактивные и управляемые плавающие интерфейсы без ручного отслеживания событий и пересчётов.

Важные нюансы

  • Middleware исполняются строго по порядку, что влияет на результат вычислений.
  • Позиция floating элемента всегда зависит от размеров reference и ограничивающих контейнеров.
  • Для сложных интерфейсов рекомендуется комбинировать flip, shift и offset для устойчивого поведения в любых условиях.

Floating UI предоставляет тонкий контроль над позиционированием и адаптивностью интерфейса, делая его идеальным инструментом для создания динамических, интерактивных элементов в современных веб-приложениях.