Управление подписками

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: расширенные возможности управления

Middleware — это функции, которые можно использовать для модификации позиции. Среди наиболее популярных:

  • offset(value) — задаёт расстояние между reference и floating элементом.
  • flip(options) — меняет сторону всплывающего элемента при ограниченном пространстве.
  • shift(options) — сдвигает элемент внутрь контейнера при угрозе выхода за пределы.
  • arrow(options) — используется для позиционирования стрелки тултипа относительно floating элемента.

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

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, с примерами отслеживания и реактивного обновления позиции в реальном времени. Это будет полноценная учебная глава для практического применения.

Хотите, чтобы я это сделал?