В 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:
aria-pressed для переключателей).aria-disabled).selectionMode).<Button
key="2"
itemKey="2"
state={state}
isDisabled={true}
>
Недоступная кнопка
</Button>
При использовании isDisabled React Aria автоматически
добавляет соответствующие атрибуты и предотвращает взаимодействие с
кнопкой через клавиатуру или мышь.
React Aria обеспечивает поддержку клавиш-стрелок для перемещения фокуса между кнопками:
Эта функциональность встроена в useButtonGroup и не
требует ручной реализации.
React Aria поддерживает несколько режимов выбора:
Пример для множественного выбора:
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>
Использование 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-библиотеками.