Floating UI предоставляет мощный механизм для управления позиционированием всплывающих элементов. Одной из ключевых возможностей является гибкое объединение нескольких взаимодействий с элементом: клики, наведение курсора, фокус и другие события. Это позволяет создавать сложные интерфейсы, такие как выпадающие меню, тултипы с задержкой или контекстные панели, сохраняя при этом контроль над положением и поведением всплывающего блока.
useInteractionsБазовым инструментом для комбинирования взаимодействий является хук
useInteractions. Он принимает массив взаимодействий
(interactions) и возвращает объект с методами для привязки
к элементам: getReferenceProps,
getFloatingProps и другие. Эти методы объединяют поведение
всех переданных взаимодействий, обеспечивая синхронную работу клика,
наведения и фокуса.
Пример:
import { useFloating, useClick, useHover, useInteractions } from '@floating-ui/react';
const MyComponent = () => {
const { x, y, reference, floating, strategy } = useFloating();
const click = useClick({ enabled: true });
const hover = useHover({ delay: 100 });
const interactions = useInteractions([click, hover]);
return (
<>
<button ref={interactions.getReferenceProps(reference)}>Открыть меню</button>
<div ref={interactions.getFloatingProps(floating)} style={{ position: strategy, top: y ?? 0, left: x ?? 0 }}>
Меню
</div>
</>
);
};
В этом примере кнопка одновременно реагирует на клик и наведение, а
useInteractions гарантирует корректное объединение
событий.
При комбинировании взаимодействий часто требуется контролировать
приоритет событий. Например, нужно, чтобы меню открывалось по клику
мгновенно, а по наведению — с задержкой. Для этого в настройках
useHover используется параметр delay, а
useClick можно включать или отключать динамически через
enabled.
const hover = useHover({ delay: { open: 200, close: 100 } });
const click = useClick({ enabled: true });
Такая конфигурация позволяет избежать конфликтов между событиями, когда один элемент реагирует на несколько типов взаимодействий.
В интерактивных формах или меню важно, чтобы элемент оставался
открытым при переходе фокуса с клавиатуры. Floating UI предоставляет
useFocus для управления этим поведением. Его удобно
комбинировать с useHover:
const hover = useHover({ delay: 100, handleClose: safePolygon });
const focus = useFocus();
const interactions = useInteractions([hover, focus]);
Функция safePolygon предотвращает закрытие меню при
движении курсора по траектории между элементами, создавая естественное
поведение, аналогичное нативным dropdown.
useRole для семантикиДля повышения доступности элементов можно подключить
useRole. Например, если всплывающее меню является списком
или тултипом, useRole назначает соответствующий
ARIA-атрибут:
const role = useRole({ role: 'menu' });
const interactions = useInteractions([click, hover, role]);
В результате элемент становится доступным для экранных читалок, а поведение взаимодействий остаётся консистентным.
Floating UI позволяет управлять закрытием через
useDismiss. Этот хук может работать совместно с другими
взаимодействиями, например, с кликом вне области или нажатием клавиши
Escape:
const dismiss = useDismiss({ outsidePress: true, escapeKey: true });
const interactions = useInteractions([click, hover, dismiss]);
Такое объединение обеспечивает, что элемент корректно закроется при любом типе взаимодействия, не конфликтуя с открытием по другим событиям.
Для вложенных меню комбинируются несколько уровней
useFloating и наборов взаимодействий:
useClick и
useHover для открытия первого уровня.handleClose на hover предотвращает преждевременное закрытие
родителя.useInteractions,
обеспечивая плавное переключение между уровнями.Пример структуры:
const parentHover = useHover({ delay: 150 });
const parentClick = useClick();
const parentInteractions = useInteractions([parentHover, parentClick]);
const childHover = useHover({ delay: 100 });
const childClick = useClick();
const childInteractions = useInteractions([childHover, childClick]);
Такой подход позволяет создать полноценное многоуровневое меню с естественным поведением для мыши и клавиатуры.
delay и handleClose для
предотвращения лишних перерендеров при быстром движении курсора.useFloating, комбинируя поведение через
useInteractions.Эти принципы помогают поддерживать отзывчивость интерфейса даже при сложных комбинированных сценариях.