Web Components

Floating UI — это библиотека, предназначенная для точного позиционирования всплывающих элементов относительно других элементов на странице. В контексте Web Components она становится особенно полезной, поскольку обеспечивает гибкость при работе с инкапсулированной разметкой и Shadow DOM.


Интеграция с Web Components

При использовании Custom Elements и Shadow DOM позиционирование всплывающих элементов сталкивается с проблемой изоляции контекста. Floating UI решает это через предоставление функций, которые принимают корень документа или конкретный контейнер, позволяя вычислять позиции даже внутри Shadow DOM.

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

class TooltipElement extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
    this.shadowRoot.innerHTML = `
      
      
    `;
  }

  connectedCallback() {
    const trigger = this.shadowRoot.querySelector('#trigger');
    const tooltip = this.shadowRoot.querySelector('#tooltip');

    trigger.addEventListener('mouseenter', async () => {
      tooltip.style.display = 'block';
      const { x, y } = await computePosition(trigger, tooltip, {
        middleware: [offset(10), flip(), shift({ padding: 5 })],
      });
      Object.assign(tooltip.style, {
        left: `${x}px`,
        top: `${y}px`,
      });
    });

    trigger.addEventListener('mouseleave', () => {
      tooltip.style.display = 'none';
    });
  }
}

customElements.define('tooltip-element', TooltipElement);

Использование middleware для точного позиционирования

Middleware в Floating UI позволяет изменять поведение позиционирования:

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

Эти функции можно комбинировать, чтобы обеспечить адаптивное и безопасное позиционирование всплывающих компонентов внутри Shadow DOM.


Работа с Shadow DOM

Floating UI умеет работать с элементами внутри Shadow DOM, если передавать правильные референсы:

const trigger = this.shadowRoot.querySelector('#trigger');
const floating = this.shadowRoot.querySelector('#tooltip');

computePosition(trigger, floating, { middleware: [offset(8), flip()] });

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


Динамическое обновление позиции

При изменении размеров окна или содержимого компонента, позиция всплывающего элемента может стать некорректной. Для этого Floating UI предоставляет autoUpdate:

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

autoUpdate(trigger, tooltip, () => {
  computePosition(trigger, tooltip, { middleware: [offset(10), flip()] })
    .then(({ x, y }) => {
      Object.assign(tooltip.style, { left: `${x}px`, top: `${y}px` });
    });
});

autoUpdate автоматически пересчитывает координаты при:

  • Скролле родительских элементов
  • Изменении размера окна
  • Изменении размеров целевого элемента или Floating элемента

Позиционирование сложных компонентов

Для многоуровневых модальных окон, кастомных dropdown и комбобоксов Floating UI позволяет:

  1. Создавать цепочку middleware для гибкой логики поведения.
  2. Использовать custom placement через placement (top, bottom-start, right-end и др.).
  3. Обрабатывать вложенные Shadow DOM с помощью прямых референсов на элементы.
computePosition(trigger, floating, {
  placement: 'bottom-start',
  middleware: [
    offset(12),
    flip({ fallbackPlacements: ['top', 'right'] }),
    shift({ padding: 5 })
  ],
});

Рекомендации по производительности

  • Не пересчитывать позицию на каждое движение мыши, используйте autoUpdate или слушатели событий resize и scroll.
  • Минимизировать количество middleware, оставляя только необходимые.
  • Позиционировать элементы только при необходимости — скрытые элементы можно полностью исключить из вычислений.

Преимущества Floating UI в Web Components

  • Полная совместимость с Shadow DOM
  • Независимость от глобальных стилей и DOM-структуры
  • Простая интеграция с любыми кастомными элементами
  • Адаптивность к изменениям viewport и содержимого
  • Гибкое управление поведением всплывающих элементов через middleware