Группы чекбоксов

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

В пользовательских интерфейсах группы чекбоксов применяются в следующих сценариях:

  • фильтрация данных
  • выбор нескольких настроек
  • формирование списков параметров
  • конфигурация пользовательских предпочтений
  • настройка уведомлений и прав доступа

Библиотека Radix UI предоставляет низкоуровневые примитивы для создания доступных, гибко настраиваемых чекбоксов. Компоненты не навязывают внешний вид и легко интегрируются в любую дизайн-систему.


Базовый компонент Checkbox

Группы чекбоксов строятся на основе компонента Checkbox.Root. Этот компонент управляет состоянием отмеченности и предоставляет все необходимые ARIA-атрибуты.

Основные части компонента:

Элемент Назначение
Checkbox.Root корневой элемент чекбокса
Checkbox.Indicator отображает индикатор выбранного состояния

Минимальный пример:

import * as Checkbox from "@radix-ui/react-checkbox";
import { CheckIcon } from "@radix-ui/react-icons";

function BasicCheckbox() {
  return (
    <Checkbox.Root className="CheckboxRoot">
      <Checkbox.Indicator className="CheckboxIndicator">
        <CheckIcon />
      </Checkbox.Indicator>
    </Checkbox.Root>
  );
}

Состояние чекбокса может быть:

  • checked
  • unchecked
  • indeterminate

Формирование группы чекбоксов

Radix UI не предоставляет отдельного компонента CheckboxGroup. Группы формируются логически — через управление состоянием нескольких чекбоксов.

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

Пример группы

import * as Checkbox from "@radix-ui/react-checkbox";
import { CheckIcon } from "@radix-ui/react-icons";
import { useState } from "react";

function CheckboxGroup() {
  const [selected, setSelected] = useState([]);

  const toggle = (value) => {
    setSelected((current) =>
      current.includes(value)
        ? current.filter((item) => item !== value)
        : [...current, value]
    );
  };

  return (
    <div>
      <label>
        <Checkbox.Root
          checked={selected.includes("react")}
          onCheckedCha nge={() => toggle("react")}
        >
          <Checkbox.Indicator>
            <CheckIcon />
          </Checkbox.Indicator>
        </Checkbox.Root>
        React
      </label>

      <label>
        <Checkbox.Root
          checked={selected.includes("vue")}
          onCheckedCha nge={() => toggle("vue")}
        >
          <Checkbox.Indicator>
            <CheckIcon />
          </Checkbox.Indicator>
        </Checkbox.Root>
        Vue
      </label>

      <label>
        <Checkbox.Root
          checked={selected.includes("angular")}
          onCheckedCha nge={() => toggle("angular")}
        >
          <Checkbox.Indicator>
            <CheckIcon />
          </Checkbox.Indicator>
        </Checkbox.Root>
        Angular
      </label>
    </div>
  );
}

Состояние группы хранится в массиве selected. Каждый чекбокс проверяет, присутствует ли его значение в этом массиве.


Управляемые и неуправляемые чекбоксы

Radix поддерживает два режима работы:

Управляемый режим

Состояние хранится во внешнем состоянии React.

<Checkbox.Root
  checked={checked}
  onCheckedCha nge={setChecked}
/>

Преимущества:

  • полный контроль состояния
  • синхронизация с сервером
  • интеграция с формами
  • возможность сложной логики

Неуправляемый режим

Компонент управляет состоянием самостоятельно.

<Checkbox.Root defaultChecked />

Подходит для простых интерфейсов, где состояние не требуется отслеживать программно.


Состояние Indeterminate

Иногда требуется показать частично выбранную группу. Для этого используется состояние indeterminate.

Пример: чекбокс “Выбрать всё”.

<Checkbox.Root
  checked={checkedItems.length === items.length}
  onCheckedCha nge={toggleAll}
>
  <Checkbox.Indicator>
    <CheckIcon />
  </Checkbox.Indicator>
</Checkbox.Root>

Если часть элементов выбрана:

checked="indeterminate"

Это визуально сигнализирует, что выбор сделан не полностью.


Реализация чекбокса “Выбрать всё”

Типичный интерфейс групп чекбоксов содержит управляющий чекбокс.

function CheckboxGroup() {
  const items = ["js", "ts", "react"];
  const [selected, setSelected] = useState([]);

  const allChecked = selected.length === items.length;
  const partiallyChecked = selected.length > 0 && !allChecked;

  const toggleAll = () => {
    setSelected(allChecked ? [] : items);
  };

  return (
    <div>
      <Checkbox.Root
        checked={partiallyChecked ? "indeterminate" : allChecked}
        onCheckedCha nge={toggleAll}
      >
        <Checkbox.Indicator>
          <CheckIcon />
        </Checkbox.Indicator>
      </Checkbox.Root>

      {items.map((item) => (
        <label key={item}>
          <Checkbox.Root
            checked={selected.includes(item)}
            onCheckedCha nge={() => toggle(item)}
          >
            <Checkbox.Indicator>
              <CheckIcon />
            </Checkbox.Indicator>
          </Checkbox.Root>
          {item}
        </label>
      ))}
    </div>
  );
}

Такая схема широко применяется в таблицах, настройках и административных панелях.


Интеграция с HTML-формами

Radix чекбоксы можно использовать в обычных формах. Для этого указывается name и value.

<Checkbox.Root
  name="framework"
  value="react"
>

При отправке формы браузер передаст выбранные значения.

Группа чекбоксов может иметь одинаковый name.

<Checkbox.Root name="skills" value="javascript" />
<Checkbox.Root name="skills" value="typescript" />
<Checkbox.Root name="skills" value="react" />

На сервере это будет обработано как массив значений.


Семантика и доступность

Radix автоматически добавляет необходимые ARIA-атрибуты:

  • role="checkbox"
  • aria-checked
  • data-state

Это делает компонент полностью совместимым со скринридерами.

Дополнительные рекомендации:

Использование label

<label>
  <Checkbox.Root />
  Email уведомления
</label>

или

<label htmlFor="notifications">
  Email уведомления
</label>

<Checkbox.Root id="notifications" />

Группировка

Для групп рекомендуется использовать fieldset.

<fieldset>
  <legend>Уведомления</legend>

  <label>
    <Checkbox.Root />
    Email
  </label>

  <label>
    <Checkbox.Root />
    SMS
  </label>
</fieldset>

Это улучшает навигацию для пользователей вспомогательных технологий.


Стилизация чекбоксов

Radix не содержит готовых стилей. Оформление выполняется через CSS.

Пример базовой стилизации:

.CheckboxRoot {
  width: 20px;
  height: 20px;
  border: 2px solid #444;
  border-radius: 4px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.CheckboxRoot[data-state="checked"] {
  background: #4f46e5;
  border-color: #4f46e5;
}

.CheckboxIndicator {
  color: white;
}

Использование data-state

Radix автоматически добавляет атрибут data-state.

Возможные значения:

  • checked
  • unchecked
  • indeterminate

Это позволяет управлять стилями без JavaScript.

.CheckboxRoot[data-state="checked"] {
  background: green;
}

.CheckboxRoot[data-state="indeterminate"] {
  background: orange;
}

Динамическая генерация групп

Чекбоксы часто создаются из массива данных.

const options = [
  { id: "js", label: "JavaScript" },
  { id: "ts", label: "TypeScript" },
  { id: "react", label: "React" }
];

Рендеринг:

{options.map(option => (
  <label key={option.id}>
    <Checkbox.Root
      checked={selected.includes(option.id)}
      onCheckedCha nge={() => toggle(option.id)}
    >
      <Checkbox.Indicator>
        <CheckIcon />
      </Checkbox.Indicator>
    </Checkbox.Root>
    {option.label}
  </label>
))}

Такой подход позволяет строить интерфейсы на основе API-данных.


Управление производительностью

При больших группах чекбоксов (например, десятки или сотни элементов) рекомендуется:

  • хранить состояние в Set
  • мемоизировать обработчики
  • использовать виртуализацию списков

Пример с Set:

const [selected, setSelected] = useState(new Set());

function toggle(value) {
  setSelected(prev => {
    const next = new Set(prev);

    if (next.has(value)) {
      next.delete(value);
    } else {
      next.add(value);
    }

    return next;
  });
}

Это ускоряет операции поиска и удаления.


Комбинирование с другими компонентами Radix

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

  • Dropdown Menu
  • Popover
  • Dialog
  • Accordion
  • Scroll Area

Пример фильтра в Popover:

<Popover.Root>
  <Popover.Trigger>Фильтр</Popover.Trigger>

  <Popover.Content>
    <CheckboxGroup />
  </Popover.Content>
</Popover.Root>

Такой паттерн широко используется в таблицах и панелях фильтрации.


Типичные сценарии использования

Фильтры интернет-магазина

  • бренды
  • категории
  • размеры
  • цвета

Настройки приложения

  • типы уведомлений
  • параметры конфиденциальности
  • функции интерфейса

Административные панели

  • права пользователей
  • доступ к модулям
  • массовые операции

Типичные ошибки

Смешивание controlled и uncontrolled состояния

Нельзя одновременно использовать:

checked
defaultChecked

Следует выбрать один режим.


Отсутствие label

Чекбокс без текстового описания ухудшает доступность.

Неправильно:

<Checkbox.Root />

Правильно:

<label>
  <Checkbox.Root />
  Получать уведомления
</label>

Некорректная обработка indeterminate

indeterminate не является булевым значением. Его нужно передавать строкой.

checked="indeterminate"

Архитектура групп чекбоксов

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

CheckboxGroup
 ├ CheckboxItem
 ├ CheckboxItem
 ├ CheckboxItem

Пример структуры:

<CheckboxGroup
  value={selected}
  onCha nge={setSelected}
>
  <CheckboxItem value="react" />
  <CheckboxItem value="vue" />
</CheckboxGroup>

Такой подход:

  • уменьшает дублирование кода
  • упрощает поддержку
  • стандартизирует поведение компонентов.

Итоговые принципы построения групп чекбоксов в Radix UI

Ключевые особенности архитектуры:

  • компонент Checkbox.Root является базовым строительным блоком
  • группы реализуются через управление состоянием
  • поддерживаются состояния checked, unchecked, indeterminate
  • Radix обеспечивает доступность и ARIA-совместимость
  • внешний вид полностью контролируется CSS
  • архитектура легко масштабируется для сложных интерфейсов и дизайн-систем