Добавление данных в state

Popper.js — это мощная библиотека для управления позиционированием всплывающих элементов относительно других элементов на странице. Основная задача библиотеки — корректно вычислять положение поппера (tooltip, dropdown, modal и т. д.) с учётом границ окна, смещения и взаимодействия с другими элементами DOM. В современных приложениях Popper.js используется совместно с фреймворками вроде React, Vue или Angular, но в чистом JavaScript она также функционирует эффективно.

Библиотека строится вокруг Popper Instance — объекта, который управляет позиционированием. Создаётся он через функцию createPopper(reference, popper, options):

import { createPopper } from '@popperjs/core';

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

const popperInstance = createPopper(reference, popper, {
  placement: 'top',
  modifiers: [
    {
      name: 'offset',
      options: {
        offset: [0, 8],
      },
    },
    {
      name: 'preventOverflow',
      options: {
        boundary: 'viewport',
      },
    },
  ],
});
  • reference — элемент, относительно которого будет позиционироваться поппер.
  • popper — всплывающий элемент.
  • placement — позиция поппера относительно reference (top, bottom, left, right, с вариациями -start и -end).
  • modifiers — массив модификаторов для управления поведением: смещениями, границами, скроллингом и т. д.

Модификаторы

Модификаторы — это ядро гибкости Popper.js. Они позволяют настраивать смещение, предотвращать выход поппера за границы экрана, управлять стратегией позиционирования (absolute или fixed) и многое другое.

Основные модификаторы:

  1. offset — задаёт смещение относительно reference.

    {
      name: 'offset',
      options: { offset: [10, 20] },
    }

    Первый параметр массива отвечает за смещение по основной оси, второй — по перекрестной.

  2. preventOverflow — предотвращает выход поппера за границы заданного контейнера.

    {
      name: 'preventOverflow',
      options: { boundary: document.body },
    }
  3. flip — позволяет автоматически менять расположение поппера, если выбранное placement не помещается на экране.

    {
      name: 'flip',
      options: { fallbackPlacements: ['top', 'right', 'bottom'] },
    }
  4. arrow — используется для стрелок поппера.

    {
      name: 'arrow',
      options: { element: '.tooltip-arrow' },
    }

Обновление state

Popper.js хранит внутреннее состояние в объекте state, который содержит данные о позиционировании, размерах элементов и вычисленных стилях. Объект state состоит из следующих ключевых полей:

  • elements{ reference, popper, arrow }
  • styles — объект с CSS-стилями для каждого элемента
  • modifiersData — данные модификаторов после расчёта
  • placement — текущее положение поппера
  • rects — размеры reference и popper

Пример чтения state:

const state = popperInstance.state;

console.log(state.placement); // 'top'
console.log(state.rects.reference.width); // ширина элемента reference

Обновление state вручную

В Popper.js state не рекомендуется изменять напрямую, однако можно использовать модификаторы для динамического обновления данных. Каждый модификатор получает доступ к state и может изменять его свойства.

const customModifier = {
  name: 'logPlacement',
  enabled: true,
  phase: 'write',
  fn({ state }) {
    console.log('Текущее положение:', state.placement);
    state.styles.popper.transform += ' rotate(5deg)';
  },
};
  • phase — этап жизненного цикла (read, main, write, afterWrite)
  • fn — функция, выполняемая на выбранной фазе
  • state — объект состояния, который можно читать и изменять

Динамическое обновление через setOptions

Если необходимо обновить смещения, placement или модификаторы после создания popper, используется метод setOptions:

popperInstance.setOptions({
  placement: 'bottom-start',
  modifiers: [
    {
      name: 'offset',
      options: { offset: [0, 16] },
    },
  ],
});

После этого автоматически пересчитывается state, и поппер обновляется.

Реактивное обновление при изменении контента

Popper.js обеспечивает автоматическое обновление при изменении размеров reference. Для этого используется метод update:

popperInstance.update();

Если reference или popper динамически изменяют размер, вызов update пересчитывает положение и стили. В современных приложениях удобно сочетать это с ResizeObserver:

const observer = new ResizeObserver(() => {
  popperInstance.update();
});

observer.observe(reference);
observer.observe(popper);

Интеграция с React и Vue

В React часто используют useEffect для создания popper:

import { createPopper } from '@popperjs/core';
import { useRef, useEffect } from 'react';

function Tooltip({ children, target }) {
  const popperRef = useRef(null);
  const instanceRef = useRef(null);

  useEffect(() => {
    instanceRef.current = createPopper(target.current, popperRef.current, {
      placement: 'right',
    });

    return () => instanceRef.current.destroy();
  }, [target]);

  return <div ref={popperRef}>{children}</div>;
}

Vue предоставляет аналогичный подход через директивы или Composition API.

Стратегии позиционирования

Popper.js поддерживает две стратегии:

  1. absolute — позиционирование относительно ближайшего position: relative/absolute контейнера.
  2. fixed — позиционирование относительно окна, игнорируя скроллинг родительских элементов.
createPopper(reference, popper, {
  strategy: 'fixed',
});

Стратегия влияет на расчёт state.rects и поведение при скролле.

Работа с границами и ограничениями

Модификатор preventOverflow позволяет задать разные типы границ:

{
  name: 'preventOverflow',
  options: {
    altAxis: true, // учитывать вторичную ось
    tether: false, // отключает «привязку» к reference
    padding: 8, // отступ от границ
  },
}

Это особенно важно для адаптивных интерфейсов, где popper должен оставаться видимым даже при малых разрешениях.

Заключение по state и динамическому позиционированию

Popper.js создаёт мощный, но управляемый механизм работы с динамическими элементами. Объект state содержит всю необходимую информацию о позиционировании, модификаторах и стилях. Основные способы работы с ним:

  • Чтение свойств для анализа текущего положения
  • Использование модификаторов для динамического изменения state
  • Вызов setOptions и update для пересчёта при изменении параметров

Эти инструменты позволяют строить сложные интерфейсы с всплывающими элементами, которые корректно реагируют на изменение размеров, скроллинг и адаптивность.