Группы кнопок

В React Aria группы кнопок реализуются через хук useButtonGroup и связанные утилиты для управления состоянием и доступностью. Основная цель — обеспечить корректную работу кнопок в составе группы с точки зрения ARIA-спецификаций и управления состоянием, включая поддержку клавиатурной навигации и экранных читалок.


Структура группы кнопок

Группа кнопок представляет собой контейнер, внутри которого располагаются отдельные кнопки. Контейнер управляет состоянием выбранной кнопки, если это требуется, и обеспечивает соответствующие ARIA-атрибуты.

Простейшая структура выглядит так:

import {useButtonGroup, useButton} from '@react-aria/button';
import {useButtonGroupState} from '@react-stately/button';
import React from 'react';

function ButtonGroupExample() {
  const state = useButtonGroupState({selectionMode: 'single'});
  const ref = React.useRef();
  const {groupProps} = useButtonGroup({}, state, ref);

  return (
    <div {...groupProps} ref={ref}>
      <Button key="1" itemKey="1" state={state}>Кнопка 1</Button>
      <Button key="2" itemKey="2" state={state}>Кнопка 2</Button>
      <Button key="3" itemKey="3" state={state}>Кнопка 3</Button>
    </div>
  );
}

function Button({itemKey, state, children}) {
  const ref = React.useRef();
  const {buttonProps} = useButton(
    {onPress: () => state.setSelectedKey(itemKey), isSelected: state.selectedKey === itemKey},
    ref
  );

  return (
    <button {...buttonProps} ref={ref}>
      {children}
    </button>
  );
}

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

  • useButtonGroupState управляет состоянием выделения кнопок.
  • selectionMode: 'single' обеспечивает возможность выбора только одной кнопки.
  • Каждый <Button> использует useButton для подключения ARIA-атрибутов и обработки событий.

Состояния кнопок в группе

Кнопки в группе могут иметь разные состояния, которые React Aria автоматически синхронизирует с ARIA:

  • selected — кнопка выбрана (aria-pressed для переключателей).
  • disabled — кнопка неактивна (aria-disabled).
  • focus — кнопка в фокусе клавиатуры (обеспечивает навигацию стрелками при selectionMode).
<Button
  key="2"
  itemKey="2"
  state={state}
  isDisabled={true}
>
  Недоступная кнопка
</Button>

При использовании isDisabled React Aria автоматически добавляет соответствующие атрибуты и предотвращает взаимодействие с кнопкой через клавиатуру или мышь.


Навигация по кнопкам с клавиатуры

React Aria обеспечивает поддержку клавиш-стрелок для перемещения фокуса между кнопками:

  • ArrowRight / ArrowDown — переход к следующей кнопке.
  • ArrowLeft / ArrowUp — переход к предыдущей кнопке.
  • Home / End — переход к первой и последней кнопке в группе.

Эта функциональность встроена в useButtonGroup и не требует ручной реализации.


Поддержка различных режимов выбора

React Aria поддерживает несколько режимов выбора:

  1. single — только одна кнопка может быть выбрана.
  2. multiple — несколько кнопок могут быть активными одновременно.
  3. none — кнопки функционируют как обычные, без состояния выбора.

Пример для множественного выбора:

const state = useButtonGroupState({selectionMode: 'multiple'});

<Button key="1" itemKey="1" state={state}>Кнопка A</Button>
<Button key="2" itemKey="2" state={state}>Кнопка B</Button>
<Button key="3" itemKey="3" state={state}>Кнопка C</Button>

В этом случае state.selectedKeys хранит массив выбранных кнопок.


Стилизация и визуальная обратная связь

React Aria не предоставляет готовую стилизацию, поэтому визуальные индикаторы состояния кнопки нужно реализовать вручную, используя state.selectedKey или state.selectedKeys.

Пример:

.button {
  padding: 8px 16px;
  border: 1px solid #ccc;
  background: white;
  cursor: pointer;
}

.button.selected {
  background: #007aff;
  color: white;
}
<button
  {...buttonProps}
  className={`button ${state.selectedKey === itemKey ? 'selected' : ''}`}
>
  {children}
</button>

Доступность (Accessibility) и ARIA-атрибуты

Использование React Aria гарантирует правильное выставление следующих атрибутов:

  • role="group" для контейнера кнопок.
  • aria-pressed для переключателей (toggle buttons).
  • aria-disabled для неактивных кнопок.
  • Поддержка tabIndex для управления фокусом.

Пример с ARIA для переключателей:

<button
  {...buttonProps}
  aria-pressed={state.selectedKey === itemKey}
>
  {children}
</button>

Динамическое добавление и удаление кнопок

React Aria корректно обновляет состояние группы при динамическом изменении списка кнопок. Использование ключей (key и itemKey) позволяет сохранять правильную синхронизацию:

{buttons.map(btn => (
  <Button key={btn.id} itemKey={btn.id} state={state}>
    {btn.label}
  </Button>
))}

Удаление или добавление кнопок автоматически обновляет state.selectedKey или state.selectedKeys.


Итог

Группы кнопок в React Aria обеспечивают консистентное управление состоянием, доступность по стандартам ARIA и полную поддержку клавиатурной навигации. Основные инструменты — это useButtonGroup, useButtonGroupState и useButton. Использование этих хуков позволяет создавать как простые одиночные группы кнопок, так и сложные интерфейсы с множественным выбором и динамическим содержимым.

Ключевое преимущество — отделение логики и состояния от визуальной части, что упрощает интеграцию с любыми стилями и UI-библиотеками.