Переход от ранних версий Popper.js к современному API (начиная с версии 2) сопровождается серьёзной переработкой архитектуры. Основной акцент сделан на модульности, расширяемости и предсказуемости поведения.
Вместо монолитного подхода используется система модификаторов (modifiers) — независимых функций, которые управляют позицией, стилями и поведением всплывающих элементов. Это позволяет гибко конфигурировать Popper и подключать только необходимые части.
Ключевое отличие:
В новой версии API основной способ создания Popper — функция
createPopper:
import { createPopper } from '@popperjs/core';
const popperInstance = createPopper(referenceElement, popperElement, {
placement: 'bottom',
});
Изменения:
new Popper(...)Методы экземпляра:
update() — пересчёт позицииforceUpdate() — принудительное обновление без
ожиданияdestroy() — уничтожение экземпляраМодификаторы — центральная часть нового API. Каждый модификатор описывается объектом:
{
name: 'offset',
options: {
offset: [0, 10],
},
}
Основные свойства модификатора:
name — уникальное имяenabled — включён/выключенphase — стадия выполненияfn — функция обработкиoptions — настройкиrequires — зависимости от других модификаторовВведена строгая последовательность фаз:
beforeReadreadafterReadbeforeMainmainafterMainbeforeWritewriteafterWriteЭто позволяет:
Пример:
const customModifier = {
name: 'custom',
phase: 'main',
fn({ state }) {
// логика изменения состояния
},
};
Свойство placement осталось, но стало более строгим и
предсказуемым:
placement: 'top-start'
Допустимые значения:
top, bottom, left,
right-start, -endИзменения:
flipРанее логика переворота (flip) была встроена. Теперь это отдельный модификатор:
{
name: 'flip',
options: {
fallbackPlacements: ['top', 'right'],
},
}
Особенности:
preventOverflowОтвечает за предотвращение выхода элемента за границы:
{
name: 'preventOverflow',
options: {
boundary: 'viewport',
},
}
Изменения:
viewport,
clippingParents, DOM-элемент)offsetРанее использовались числовые значения, теперь — массив:
{
name: 'offset',
options: {
offset: [skidding, distance],
},
}
Где:
skidding — смещение по основной осиdistance — расстояние от reference-элементаТакже поддерживаются функции:
offset: ({ placement }) => {
return placement === 'top' ? [0, 20] : [0, 10];
}
Вместо прямого управления стилями введён модификатор
computeStyles:
{
name: 'computeStyles',
options: {
adaptive: true,
gpuAcceleration: true,
},
}
И модификатор applyStyles:
{
name: 'applyStyles',
}
Разделение ответственности:
computeStyles — вычисляет стилиapplyStyles — применяет их к DOMЭто даёт возможность:
Добавлена поддержка виртуальных reference-элементов:
const virtualElement = {
getBoundingClientRect: () => ({
width: 0,
height: 0,
top: 100,
left: 100,
right: 100,
bottom: 100,
}),
};
Использование:
createPopper(virtualElement, popperElement);
Применение:
Новая модель обновлений:
popperInstance.update();
Особенности:
Принудительное обновление:
popperInstance.forceUpdate();
Из API удалены или переработаны:
gpuAcceleration (перенесён в
computeStyles)boundariesElement (заменён на
boundary)modifiers в старом форматеeventsEnabled (заменён на модификаторы событий)Теперь обработка событий реализуется через модификатор
eventListeners:
{
name: 'eventListeners',
options: {
scroll: true,
resize: true,
},
}
Изменения:
Новый API позволяет легко создавать собственные модификаторы:
const myModifier = {
name: 'myModifier',
enabled: true,
phase: 'main',
requires: ['offset'],
fn({ state }) {
state.styles.popper.backgroundColor = 'red';
},
};
Подключение:
createPopper(reference, popper, {
modifiers: [myModifier],
});
state)Внутреннее состояние Popper стало доступным и структурированным:
state = {
placement,
elements,
rects,
modifiersData,
styles,
attributes,
};
Это даёт:
Ключевые изменения:
Результат:
Основные шаги при переходе:
new Popper на createPopperТипичный пример миграции:
Было:
new Popper(reference, popper, {
modifiers: {
offset: { offset: '0,10' },
},
});
Стало:
createPopper(reference, popper, {
modifiers: [
{
name: 'offset',
options: {
offset: [0, 10],
},
},
],
});