useButton для кнопок

useButton — это хук из библиотеки React Aria, предназначенный для управления поведением кнопок и обеспечения доступности (accessibility) в приложениях на React. Он инкапсулирует стандартные практики ARIA, управление событиями и клавиатурные взаимодействия, освобождая разработчика от необходимости вручную писать сложные обработчики.

Хук подходит не только для обычных <button>, но и для кастомных элементов, имитирующих кнопки (например, <div> или <span> с ролью button).


Импорт и базовое использование

import { useButton } from '@react-aria/button';
import { useRef } from 'react';

function MyButton(props) {
  let ref = useRef();
  let { buttonProps, isPressed } = useButton(props, ref);

  return (
    <button {...buttonProps} ref={ref}>
      {isPressed ? 'Нажата' : 'Нажмите меня'}
    </button>
  );
}

Ключевые моменты:

  • buttonProps — объект с готовыми пропсами для кнопки, включающий обработчики событий и ARIA-атрибуты.
  • ref — ссылка на DOM-элемент, обязательная для корректной работы хука.
  • isPressed — булевый флаг, указывающий на состояние нажатия кнопки.

Поддержка кастомных элементов

Если кнопка реализуется не через <button>, а через произвольный элемент, важно добавить role="button" и правильно обработать клавиатурные события:

function CustomButton(props) {
  let ref = useRef();
  let { buttonProps, isPressed } = useButton(props, ref);

  return (
    <div {...buttonProps} ref={ref} role="button" tabIndex={0} style={{ padding: '8px', border: '1px solid black', display: 'inline-block' }}>
      {isPressed ? 'Активно' : 'Кликни'}
    </div>
  );
}

Особенности:

  • tabIndex={0} позволяет элементу быть фокусируемым через клавиатуру.
  • Хук автоматически добавляет обработку Enter и Space для активации кнопки.

Работа с событиями

useButton упрощает работу с основными событиями:

  • onPress — срабатывает при клике или активации через клавиатуру.
  • onPressStart и onPressEnd — для отслеживания начала и конца нажатия.
  • onPressChange — вызывается при смене состояния нажатия (true / false).
function AdvancedButton() {
  let ref = useRef();
  let { buttonProps, isPressed } = useButton({
    onPress: () => console.log('Кнопка активирована'),
    onPressStart: () => console.log('Начало нажатия'),
    onPressEnd: () => console.log('Конец нажатия'),
  }, ref);

  return <button {...buttonProps} ref={ref}>{isPressed ? 'Нажата' : 'Кнопка'}</button>;
}

Важно: onPress объединяет мышь, клавиатуру и сенсорные устройства в одно событие, обеспечивая универсальное поведение.


ARIA и доступность

useButton автоматически добавляет:

  • aria-pressed для кнопок типа toggle.
  • disabled для неактивных кнопок.
  • Клавиатурную поддержку (Enter и Space) для кастомных элементов.
function ToggleButton() {
  let ref = useRef();
  let [isSelected, setIsSelected] = useState(false);
  let { buttonProps } = useButton({
    onPress: () => setIsSelected(!isSelected),
    isPressed: isSelected
  }, ref);

  return <button {...buttonProps} ref={ref}>{isSelected ? 'Включено' : 'Выключено'}</button>;
}

Выделение ключевых моментов:

  • Для переключателей ARIA автоматически устанавливает aria-pressed.
  • Поддерживается состояние disabled через isDisabled в пропсах.

Дополнительные возможности

  • Состояние фокуса: хук управляет визуальным и логическим фокусом.
  • Совместимость с usePress: можно комбинировать с низкоуровневым хуком usePress для детальной настройки поведения нажатия.
  • Поддержка сенсорных экранов и устройств assistive technology без дополнительных действий.

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

function IconButton({ icon, label, onClick }) {
  let ref = useRef();
  let { buttonProps, isPressed } = useButton({ onPress: onClick }, ref);

  return (
    <div {...buttonProps} ref={ref} role="button" aria-label={label} tabIndex={0} style={{
      display: 'inline-flex',
      alignItems: 'center',
      padding: '6px',
      border: '1px solid gray',
      background: isPressed ? '#eee' : '#fff',
      cursor: 'pointer'
    }}>
      {icon}
    </div>
  );
}

Особенности:

  • aria-label обеспечивает корректное озвучивание кнопки для скринридеров.
  • Состояние isPressed позволяет визуально отображать нажатие.
  • Кастомная кнопка полностью доступна, несмотря на отсутствие <button>.

Основные рекомендации при работе с useButton

  1. Всегда использовать ref на DOM-элемент.
  2. Для кастомных элементов добавлять role="button" и tabIndex={0}.
  3. Использовать onPress вместо onClick для универсального поведения.
  4. Для переключателей передавать isPressed для синхронизации состояния с ARIA.
  5. Не дублировать обработку клавиатурных событий — хук делает это автоматически.

useButton обеспечивает безопасное и доступное управление кнопками в React-приложениях, сокращая код и соблюдая стандарты ARIA без необходимости вручную прописывать события и атрибуты.