useRadio и useRadioGroup

Библиотека React Aria предоставляет хуки для управления доступностью и поведением интерактивных элементов в React-приложениях. Среди них особое место занимает сочетание useRadio и useRadioGroup, предназначенное для создания групп радиокнопок с корректной поддержкой ARIA и удобной навигацией с клавиатуры.

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


useRadioGroup: структура и основные параметры

Хук useRadioGroup возвращает набор свойств и функций, необходимых для корректного рендеринга и управления группой радиокнопок:

import { useRadioGroup } from '@react-aria/radio';

const { radioGroupProps, labelProps } = useRadioGroup({
  name: 'options',
  value: selectedValue,
  onChange: setSelectedValue,
  isDisabled: false,
});

Основные параметры:

  • name — имя группы, используется для объединения радиокнопок в одну логическую группу.
  • value — текущее выбранное значение.
  • onChange — функция обратного вызова, вызываемая при смене выбранной кнопки.
  • isDisabled — флаг, запрещающий взаимодействие с группой.
  • orientation — ориентация группы: "horizontal" или "vertical". Влияет на поведение клавиш навигации.

Возвращаемые свойства:

  • radioGroupProps — props для контейнера радиогруппы, включающие роли ARIA и обработчики клавиатуры.
  • labelProps — props для подписи группы, которые нужно передать элементу <label>.

useRadio: создание отдельной радиокнопки

Хук useRadio принимает параметры отдельной кнопки и связывается с родительской группой через контекст.

import { useRadio } from '@react-aria/radio';
import { useRadioGroupState } from '@react-stately/radio';

const state = useRadioGroupState({ value: selectedValue, onChange: setSelectedValue });

const { inputProps } = useRadio({ value: 'option1', isDisabled: false }, state);

Параметры useRadio:

  • value — значение радиокнопки, передаваемое в родительскую группу.
  • isDisabled — отключение конкретной кнопки.
  • children — необязательная подпись радиокнопки.

Возвращаемые свойства:

  • inputProps — props для <input type="radio">, включающие ARIA-атрибуты, обработчики событий и синхронизацию с состоянием группы.
  • isSelected — булевое значение, показывающее, выбрана ли кнопка.

Пример интеграции useRadioGroup и useRadio

Пример с вертикальной группой радиокнопок с обработкой изменения значения:

import React, { useState } from 'react';
import { useRadioGroup, useRadio } from '@react-aria/radio';
import { useRadioGroupState } from '@react-stately/radio';

function RadioButton({ value, children, state }) {
  const { inputProps, isSelected } = useRadio({ value }, state);
  return (
    <label style={{ display: 'block', margin: '4px 0' }}>
      <input {...inputProps} />
      {children} {isSelected ? '(выбрано)' : ''}
    </label>
  );
}

export default function RadioGroupExample() {
  const [selectedValue, setSelectedValue] = useState('option1');
  const state = useRadioGroupState({ value: selectedValue, onChange: setSelectedValue });
  const { radioGroupProps, labelProps } = useRadioGroup({ name: 'example', value: selectedValue, onChange: setSelectedValue });

  return (
    <div {...radioGroupProps}>
      <div {...labelProps}>Выберите опцию:</div>
      <RadioButton value="option1" state={state}>Опция 1</RadioButton>
      <RadioButton value="option2" state={state}>Опция 2</RadioButton>
      <RadioButton value="option3" state={state}>Опция 3</RadioButton>
    </div>
  );
}

В этом примере каждая радиокнопка получает синхронизированное состояние через useRadioGroupState, а useRadio гарантирует корректное управление ARIA и обработку навигации с клавиатуры.


Важные моменты и рекомендации

  • ARIA-совместимость: useRadioGroup автоматически устанавливает role="radiogroup", а useRadio — role="radio". Это позволяет экранным читалкам корректно озвучивать элементы.
  • Навигация с клавиатуры: стрелки вверх/вниз (или влево/вправо в горизонтальной ориентации) перемещают фокус между кнопками, а пробел или Enter выбирает текущую.
  • Состояние disabled: можно отключить отдельные кнопки или всю группу, что автоматически корректно обновляет доступность для скринридеров.
  • Контейнерная стилизация: <div {...radioGroupProps}> обеспечивает управление фокусом и роль радиогруппы; не рекомендуется оборачивать в произвольные элементы без применения props.

Расширенные возможности

  • Поддержка кастомных компонентов: useRadio и useRadioGroup позволяют строить визуально произвольные радиокнопки, передавая inputProps элементу <input> или скрывая его с помощью CSS и оборачивая кастомным компонентом.
  • Управление состоянием через useRadioGroupState: упрощает хранение выбранного значения и работу с контролируемыми/неконтролируемыми компонентами.
  • Ориентация и вложенность: можно создавать вложенные группы с различной ориентацией без нарушения логики клавиатурной навигации.

Практический паттерн для крупных форм

  1. Создать состояние группы через useRadioGroupState.
  2. Получить props группы и label через useRadioGroup.
  3. Для каждой радиокнопки использовать useRadio, передавая состояние группы.
  4. Расставить label и input с учетом визуальной и ARIA-совместимости.
  5. Применить стили для обозначения выбранной кнопки и состояния focus.

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