Floating UI — это библиотека для управления позиционированием плавающих элементов в веб-интерфейсах. В контексте Sel ect-компонента она используется для создания выпадающих списков с динамическим размещением относительно поля ввода, кнопки или любого другого триггера.
Для начала нужно определить триггер (обычно
или ) и
плавающий контейнер с опциями:
import { computePosition, offset, flip, shift } fr om '@floating-ui/dom';
const trigger = document.querySelector('#sel ect-trigger');
const dropdown = document.querySelector('#select-dropdown');
trigger.addEventListener('click', async () => {
const { x, y } = await computePosition(trigger, dropdown, {
middleware: [offset(4), flip(), shift({ padding: 8 })],
});
Object.assign(dropdown.style, {
left: `${x}px`,
top: `${y}px`,
position: 'absolute',
});
dropdown.classList.toggle('show');
});
Ключевые моменты:
offset(4) добавляет отступ между триггером и выпадающим
списком.flip() автоматически меняет позицию при нехватке
места.shift({ padding: 8 }) корректирует позицию, чтобы
элемент не выходил за границы видимой области.Для Select-компонента важно, чтобы ширина списка соответствовала ширине триггера или имела ограничение по максимальной ширине:
dropdown.style.minWidth = `${trigger.offsetWidth}px`;
dropdown.style.maxHeight = '300px';
dropdown.style.overflowY = 'auto';
Использование overflowY: auto позволяет прокручивать
длинные списки без выхода за границы экрана.
При изменении размеров окна позиция выпадающего списка может
смещаться. Для этого Floating UI предоставляет функцию
autoUpdate:
import { autoUpdate } fr om '@floating-ui/dom';
autoUpdate(trigger, dropdown, () => {
computePosition(trigger, dropdown, {
middleware: [offset(4), flip(), shift({ padding: 8 })],
}).then(({ x, y }) => {
Object.assign(dropdown.style, {
left: `${x}px`,
top: `${y}px`,
});
});
});
Это гарантирует, что Sel ect-компонент всегда корректно позиционируется при скролле или ресайзе.
Для Select-компонента важно обеспечить доступность. Используется обработка клавиш:
let currentIndex = -1;
const options = dropdown.querySelectorAll('.option');
trigger.addEventListener('keydown', (e) => {
if (e.key === 'ArrowDown') {
currentIndex = (currentIndex + 1) % options.length;
options[currentIndex].focus();
e.preventDefault();
} else if (e.key === 'ArrowUp') {
currentIndex = (currentIndex - 1 + options.length) % options.length;
options[currentIndex].focus();
e.preventDefault();
} else if (e.key === 'Enter') {
options[currentIndex]?.click();
}
});
Фокус управляется вручную, что обеспечивает корректную работу с
aria-атрибутами.
Floating UI поддерживает создание собственных middleware для управления позиционированием:
const preventOverflow = ({ x, y, rects }) => {
const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;
return {
x: Math.min(Math.max(x, 0), viewportWidth - rects.floating.width),
y: Math.min(Math.max(y, 0), viewportHeight - rects.floating.height),
};
};
computePosition(trigger, dropdown, {
middleware: [offset(4), flip(), shift(), preventOverflow],
});
Это полезно для реализации нестандартного поведения, например, предотвращения выхода списка за границы контейнера.
Floating UI управляет только позиционированием, но комбинация с CSS-переходами позволяет создавать плавное раскрытие списка:
#select-dropdown {
opacity: 0;
transform: translateY(-5px);
transition: opacity 0.2s ease, transform 0.2s ease;
}
#select-dropdown.show {
opacity: 1;
transform: translateY(0);
}
С помощью JS-класса show и вычисленной позиции
достигается плавное открытие и закрытие.
Для React, Vue или Svelte Floating UI предоставляет соответствующие
обёртки, например @floating-ui/react-dom:
import { useFloating, offset, flip, shift } fr om '@floating-ui/react-dom';
const { x, y, reference, floating, strategy } = useFloating({
middleware: [offset(4), flip(), shift({ padding: 8 })],
});
return (
<>
- Option 1
- Option 2
>
);
Это упрощает интеграцию Floating UI с компонентами UI и управлением состоянием.
Для больших списков можно комбинировать Floating UI с виртуализацией и фильтрацией:
maxHeight и
overflowY.Использование Floating UI позволяет управлять любыми нестандартными сценариями Select-компонента, включая кастомные смещения, мультирежимные триггеры и адаптивное позиционирование на мобильных устройствах.