useFocus хук

Хук useFocus в библиотеке Floating UI предназначен для управления фокусом в компонентах пользовательского интерфейса, особенно когда речь идёт о всплывающих элементах, таких как тултипы, поповеры и модальные окна. Он обеспечивает корректное поведение фокуса при открытии и закрытии этих элементов, предотвращает потерю фокуса и управляет его возвратом к исходному элементу.

useFocus возвращает объект с несколькими ключевыми свойствами и методами, которые позволяют интегрировать фокус с логикой отображения Floating UI:

const { isFocused, getReferenceProps, getFloatingProps } = useFocus({ ...options });
  • isFocused — булевое значение, указывающее, находится ли в данный момент фокус на целевом элементе или внутри него.
  • getReferenceProps — функция для передачи пропсов элементу, который инициирует фокус (например, кнопке открытия поповера).
  • getFloatingProps — функция для передачи пропсов на сам всплывающий элемент, чтобы правильно отслеживать и сохранять фокус внутри него.

Настройка и основные параметры

useFocus поддерживает несколько опций, которые позволяют гибко настраивать поведение фокуса:

  • enabled (по умолчанию true) — включает или отключает отслеживание фокуса.
  • initialFocus — указывает элемент внутри Floating UI, на который будет установлен фокус при открытии. Это может быть CSS-селектор или React ref.
  • returnFocus (по умолчанию true) — возвращает фокус к исходному элементу после закрытия всплывающего окна.
  • preventScroll — предотвращает автоматическую прокрутку при установке фокуса на элемент.

Пример использования:

const { isFocused, getReferenceProps, getFloatingProps } = useFocus({
  initialFocus: () => firstInputRef.current,
  returnFocus: true,
});

Интеграция с Floating UI

useFocus идеально комбинируется с другими хуками Floating UI, такими как useFloating, useInteractions и useDismiss. С помощью useInteractions можно объединить обработку кликов, ховеров и фокуса в одном объекте пропсов:

const floating = useFloating({
  placement: 'bottom-start',
});

const focus = useFocus({ returnFocus: true });
const dismiss = useDismiss(floating.context);

const interactions = useInteractions([focus, dismiss]);

return (
  <>
    <button {...interactions.getReferenceProps({ ref: referenceRef })}>
      Открыть меню
    </button>
    {isOpen && (
      <div {...interactions.getFloatingProps({ ref: floatingRef })}>
        <input ref={firstInputRef} placeholder="Введите текст" />
        <button>Подтвердить</button>
      </div>
    )}
  </>
);

В этом примере useFocus обеспечивает, что фокус автоматически перейдет на первый элемент внутри поповера при его открытии, и вернется к кнопке после закрытия.


Контроль поведения фокуса

useFocus позволяет решать следующие задачи:

  1. Автоматическая установка фокуса Используя initialFocus, можно указать элемент для фокуса сразу после открытия Floating UI.

  2. Сохранение фокуса внутри всплывающего окна При попытке переместить фокус вне компонента хук предотвращает его потерю, что важно для модальных окон и меню.

  3. Возврат фокуса к исходному элементу Когда всплывающее окно закрывается, фокус возвращается на элемент, с которого оно было вызвано, что улучшает навигацию с клавиатуры и доступность.

  4. Совместимость с клавиатурными событиями useFocus корректно работает с Tab и Shift+Tab, обеспечивая циклическое перемещение фокуса внутри всплывающего компонента.


Примеры продвинутого использования

Фокус на динамически добавленные элементы

const [items, setItems] = useState([]);
const { getFloatingProps } = useFocus({
  initialFocus: () => floatingRef.current?.querySelector('input'),
});

useEffect(() => {
  if (items.length > 0) {
    floatingRef.current.querySelector('input')?.focus();
  }
}, [items]);

Комбинация с анимациями открытия/закрытия

const { isFocused, getFloatingProps } = useFocus({
  returnFocus: true,
});

return (
  <motion.div
    {...getFloatingProps()}
    initial={{ opacity: 0 }}
    animate={{ opacity: 1 }}
    exit={{ opacity: 0 }}
  >
    <input />
  </motion.div>
);

В этом случае useFocus гарантирует, что фокус будет установлен на input даже при анимации открытия всплывающего компонента.


Ключевые моменты для работы с useFocus

  • Использовать initialFocus для указания конкретного элемента фокуса.
  • Всегда комбинировать с getReferenceProps и getFloatingProps для корректного отслеживания.
  • returnFocus повышает доступность интерфейса и удобство работы с клавиатурой.
  • Можно интегрировать с другими хуками Floating UI для комплексного управления интерактивными элементами.

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