Popper.js — это мощная библиотека для управления позиционированием всплывающих элементов относительно целевых элементов на странице. В контексте date picker она используется для корректного отображения календаря рядом с полем ввода даты, с учётом видимой области окна браузера и возможных смещений.
Для начала необходимо импортировать Popper.js и инициализировать экземпляр Popper:
import { createPopper } from '@popperjs/core';
const input = document.querySelector('#date-input');
const calendar = document.querySelector('#calendar');
const popperInstance = createPopper(input, calendar, {
placement: 'bottom-start',
modifiers: [
{
name: 'offset',
options: {
offset: [0, 8], // смещение по оси X и Y
},
},
{
name: 'preventOverflow',
options: {
boundary: 'viewport', // предотвращение выхода за видимую область
},
},
{
name: 'flip',
options: {
fallbackPlacements: ['top-start', 'right-start'], // варианты размещения при нехватке места
},
},
],
});
Ключевые моменты:
placement определяет основное положение календаря
относительно поля ввода. Например, bottom-start размещает
календарь снизу слева.offset позволяет добавить дополнительное
расстояние между полем ввода и календарем.preventOverflow гарантирует, что календарь
не выйдет за границы видимой области.flip автоматически меняет позицию
календаря, если изначальная не помещается.Date picker часто открывается и закрывается при кликах или фокусе.
Для корректного позиционирования при изменении размеров окна или скролле
необходимо вызывать метод update:
input.addEventListener('focus', () => {
calendar.style.display = 'block';
popperInstance.update();
});
window.addEventListener('resize', () => {
popperInstance.update();
});
Метод update пересчитывает позицию календаря
относительно поля ввода и учитывает все модификаторы.
Иногда календарь должен размещаться внутри ограниченного контейнера.
Можно использовать модификатор preventOverflow с параметром
padding, чтобы добавить отступы от границ:
{
name: 'preventOverflow',
options: {
boundary: '#datepicker-container',
padding: 10,
},
}
Это предотвращает частичное обрезание календаря и учитывает внутренние отступы контейнера.
Для плавного появления календаря важно синхронизировать анимацию с обновлением позиции:
input.addEventListener('focus', () => {
calendar.classList.add('show'); // CSS анимация
popperInstance.update();
});
input.addEventListener('blur', () => {
calendar.classList.remove('show');
});
Использование update гарантирует, что позиция будет
пересчитана перед началом анимации, предотвращая дергание элемента.
Можно реализовать смещение не только по осям, но и с учетом размеров календаря:
const customOffset = {
name: 'offset',
options: {
offset: ({ reference, popper }) => {
const x = 0;
const y = reference.height + 4; // 4px дополнительного отступа
return [x, y];
},
},
};
Такой подход позволяет динамически изменять расстояние в зависимости от размеров поля ввода или календаря.
Для долгих страниц календарь может уехать за пределы видимой области.
Модификатор preventOverflow вместе с flip
обеспечивает автоматический перенос:
modifiers: [
{
name: 'flip',
options: {
fallbackPlacements: ['top-start', 'bottom-end'],
},
},
{
name: 'preventOverflow',
options: {
mainAxis: true,
altAxis: true,
},
},
]
mainAxis контролирует смещение по основной оси
(например, вертикально для bottom-start).altAxis контролирует смещение по противоположной оси,
предотвращая горизонтальное обрезание.Если календарь содержит динамические элементы (например, смена месяцев), необходимо пересчитывать позицию после каждого изменения:
function renderMonth() {
calendar.innerHTML = generateMonthHTML();
popperInstance.update(); // пересчет позиции после изменения содержимого
}
Это гарантирует, что Popper всегда корректно учитывает новые размеры календаря.
strategy: 'fixed' для календарей, которые
не должны смещаться при скролле родителя.update при прокрутке с
помощью requestAnimationFrame.offset, flip и
preventOverflow.Popper.js позволяет построить гибкую и адаптивную систему позиционирования date picker с поддержкой всех сценариев: ограниченные контейнеры, динамический контент, анимации и адаптивное поведение при скролле и изменении окна. Такой подход обеспечивает стабильное и корректное отображение календаря в любых условиях.