Индетерминантное состояние

Индетерминантное состояние (indeterminate state) является ключевым понятием при работе с компонентами пользовательского интерфейса, такими как чекбоксы и переключатели, особенно когда требуется отображать промежуточное состояние выбора. В React Aria оно реализуется через свойства и хуки, которые обеспечивают доступность и согласованность поведения компонента с ARIA-стандартами.


Определение и назначение

Индетерминантное состояние обозначает частичное или неопределённое состояние выбора. Классический пример — чекбокс, связанный с группой элементов, где не все элементы выбраны:

[ ] Выбрать все
  [x] Элемент 1
  [ ] Элемент 2
  [x] Элемент 3

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

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

  • Отличие от checked/unchecked: indeterminate не равен ни true, ни false.
  • Влияние на визуализацию: обычно отображается в виде горизонтальной линии или заливки, отличающейся от стандартного галочки.
  • ARIA-совместимость: для экранных читалок важно корректно указывать aria-checked="mixed".

Использование useCheckbox с индетерминантным состоянием

В React Aria для работы с чекбоксами используется хук useCheckbox. Для задания индетерминантного состояния необходимо использовать свойство isIndeterminate. Пример:

import { useCheckbox } from '@react-aria/checkbox';
import { useRef } from 'react';

function Checkbox({ isIndeterminate, ...props }) {
  let ref = useRef();
  let { inputProps } = useCheckbox({ ...props, isIndeterminate }, ref);

  return <input {...inputProps} ref={ref} />;
}

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

  • Синхронизация состояния: isIndeterminate можно вычислять на основе состояния группы дочерних чекбоксов.
  • Реактивность: при изменении выбора дочерних элементов индетерминантное состояние обновляется автоматически.

Индетерминантное состояние в группах чекбоксов

Часто требуется контролировать состояние всей группы через верхний чекбокс:

  1. Все элементы выбраны: главный чекбокс — checked = true.
  2. Ни один элемент не выбран: главный чекбокс — checked = false.
  3. Выбраны некоторые элементы: главный чекбокс — isIndeterminate = true.

Пример реализации:

import { useState } from 'react';
import { useCheckboxGroup, useCheckbox } from '@react-aria/checkbox';

function CheckboxGroup({ items }) {
  const [selected, setSelected] = useState([]);
  
  const toggleItem = (item) => {
    setSelected((prev) =>
      prev.includes(item)
        ? prev.filter(i => i !== item)
        : [...prev, item]
    );
  };

  const allSelected = selected.length === items.length;
  const someSelected = selected.length > 0 && selected.length < items.length;

  return (
    <div>
      <Checkbox
        isIndeterminate={someSelected}
        isSelected={allSelected}
        onCha nge={() =>
          allSelected ? setSelected([]) : setSelected([...items])
        }
      >
        Выбрать все
      </Checkbox>
      {items.map(item => (
        <Checkbox
          key={item}
          isSelected={selected.includes(item)}
          onCha nge={() => toggleItem(item)}
        >
          {item}
        </Checkbox>
      ))}
    </div>
  );
}

Выводы по использованию:

  • React Aria заботится о доступности: все чекбоксы получают корректные aria-checked атрибуты.
  • Индетерминантное состояние легко вычисляется из длины массива выбранных элементов.
  • Изменение главного чекбокса корректно обновляет все дочерние элементы.

Визуальная и семантическая реализация

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

  1. Семантика для ARIA:
<input
  type="checkbox"
  checked={checked}
  ref={ref}
  aria-checked={isIndeterminate ? 'mixed' : checked}
/>
  • aria-checked="mixed" позволяет экранным читалкам корректно озвучивать промежуточное состояние.
  1. Визуальная часть:
  • Обычно рисуется горизонтальная линия или частичная заливка.
  • React Aria не накладывает конкретный стиль, предоставляя контроль разработчику.
input[type="checkbox"]:indeterminate {
  background-color: #666;
}

Важно помнить, что HTML не поддерживает установку indeterminate через атрибуты напрямую. Нужно использовать свойство DOM:

ref.current.indeterminate = isIndeterminate;

React Aria автоматически синхронизирует этот атрибут при использовании useCheckbox.


Использование в других компонентах

Индетерминантное состояние применимо не только к чекбоксам:

  • TreeView: узлы дерева могут быть частично выбраны.
  • Multi-select списки: при частичном выборе отображение смешанного состояния помогает пользователю понять текущий выбор.
  • Формы с группами опций: повышает понятность интерфейса и доступность.

Советы по проектированию

  • Всегда использовать aria-checked="mixed" при indeterminate.
  • Обновление состояния должно быть атомарным и синхронизированным с дочерними элементами.
  • Индетерминантное состояние не является контролируемым пользователем напрямую; оно вычисляется из состояния группы.

Эта практика обеспечивает удобный, понятный и доступный интерфейс, полностью соответствующий стандартам WAI-ARIA и рекомендациям по доступности.