useFocus и события фокуса

Хук useFocus предназначен для управления фокусом на элементах интерфейса в приложениях на React с соблюдением доступности (a11y). Он позволяет отслеживать состояние фокуса, а также правильно реагировать на события focus и blur без необходимости вручную подписываться на DOM-события.

import {useFocus} from '@react-aria/interactions';

function FocusableButton() {
  let {focusProps, isFocused} = useFocus({});
  
  return (
    <button {...focusProps}>
      {isFocused ? 'В фокусе' : 'Не в фокусе'}
    </button>
  );
}
  • focusProps — объект с обработчиками событий (onFocus, onBlur), который необходимо применить к элементу.
  • isFocused — булево значение, показывающее текущее состояние фокуса элемента.

Настройка и обработка событий

Хук позволяет не только отслеживать фокус, но и добавлять кастомные обработчики событий:

let {focusProps, isFocused} = useFocus({
  onFocusChange: (focused) => {
    console.log('Состояние фокуса:', focused);
  }
});
  • onFocusChange вызывается при каждом изменении состояния фокуса.
  • Внутри можно выполнять действия, зависящие от того, находится элемент в фокусе или нет.

Взаимодействие с клавиатурой

useFocus корректно работает с клавиатурными навигациями, такими как Tab и Shift+Tab, обеспечивая:

  • Отслеживание фокуса без конфликтов с мышью.
  • Возможность подсветки активного элемента или запуска анимации при получении фокуса.
function InputField() {
  let {focusProps, isFocused} = useFocus({});
  
  return (
    <input
      {...focusProps}
      style={{borderColor: isFocused ? 'blue' : 'gray'}}
    />
  );
}
  • Применение динамического стиля в зависимости от isFocused позволяет визуально выделять активный элемент.

Составные компоненты и вложенные фокусы

Для сложных компонентов, например, комбинированных кнопок или полей ввода с иконками, useFocus помогает отслеживать фокус на корневом элементе, не требуя отдельных обработчиков для каждого вложенного элемента:

function CompositeButton() {
  let {focusProps, isFocused} = useFocus({});
  
  return (
    <div {...focusProps} tabIndex={0} style={{outline: isFocused ? '2px solid red' : 'none'}}>
      <span>Иконка</span>
      <span>Текст кнопки</span>
    </div>
  );
}
  • tabIndex={0} делает контейнер фокусируемым.
  • Любой фокус внутри контейнера отслеживается через isFocused.

Объединение с другими хуками React Aria

useFocus часто используется совместно с хуками вроде useHover или usePress для создания интерактивных компонентов с полным набором событий:

import {useHover} from '@react-aria/interactions';

function InteractiveCard() {
  let {focusProps, isFocused} = useFocus({});
  let {hoverProps, isHovered} = useHover({});
  
  return (
    <div
      {...focusProps}
      {...hoverProps}
      style={{
        border: isFocused ? '2px solid blue' : isHovered ? '2px solid gray' : '1px solid black'
      }}
      tabIndex={0}
    >
      Карточка
    </div>
  );
}
  • Комбинирование хуков позволяет управлять визуальными состояниями: фокус, наведение мыши, нажатие.

Практические рекомендации

  • Всегда применять focusProps на элемент, который должен быть фокусируемым.
  • Не использовать onFocus и onBlur напрямую, если уже применен focusProps, чтобы избежать конфликтов.
  • Для визуальных эффектов использовать isFocused, а не :focus CSS, что повышает контроль над состоянием через JavaScript.
  • В сложных компонентах с несколькими интерактивными частями рекомендуется оборачивать их в контейнер с tabIndex=0 и использовать один useFocus, чтобы управлять фокусом централизованно.

Отличие от стандартных событий focus/blur

  • useFocus обеспечивает согласованное поведение на всех браузерах и устройствах, включая мобильные.
  • Поддерживает виртуальный фокус, который может использоваться в компонентах с кастомной навигацией (например, в списках и таблицах).
  • Позволяет объединять управление фокусом с другими взаимодействиями через React Aria API, минимизируя ручное управление DOM-событиями.

Продвинутые сценарии

  1. Фокус внутри модальных окон: useFocus можно комбинировать с useModal для отслеживания активного элемента при открытом модальном диалоге.
  2. Списки и сетки: в сочетании с useListBox или useGrid позволяет управлять фокусом по элементам без дублирования логики.
  3. Доступность для клавиатуры: хук корректно обрабатывает события Tab, Shift+Tab, ArrowKeys, обеспечивая соответствие стандартам ARIA.

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