Группы чекбоксов используются для выбора нескольких независимых значений из набора вариантов. В отличие от радиокнопок, где допускается только один активный вариант, чекбоксы позволяют включать любое количество элементов.
В пользовательских интерфейсах группы чекбоксов применяются в следующих сценариях:
Библиотека Radix UI предоставляет низкоуровневые примитивы для создания доступных, гибко настраиваемых чекбоксов. Компоненты не навязывают внешний вид и легко интегрируются в любую дизайн-систему.
Группы чекбоксов строятся на основе компонента
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>
);
}
Состояние чекбокса может быть:
checkeduncheckedindeterminateRadix 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.
Пример: чекбокс “Выбрать всё”.
<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>
);
}
Такая схема широко применяется в таблицах, настройках и административных панелях.
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-checkeddata-stateЭто делает компонент полностью совместимым со скринридерами.
Дополнительные рекомендации:
<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;
}
Radix автоматически добавляет атрибут data-state.
Возможные значения:
checkeduncheckedindeterminateЭто позволяет управлять стилями без 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;
});
}
Это ускоряет операции поиска и удаления.
Группы чекбоксов часто используются совместно с другими примитивами:
Пример фильтра в Popover:
<Popover.Root>
<Popover.Trigger>Фильтр</Popover.Trigger>
<Popover.Content>
<CheckboxGroup />
</Popover.Content>
</Popover.Root>
Такой паттерн широко используется в таблицах и панелях фильтрации.
Нельзя одновременно использовать:
checked
defaultChecked
Следует выбрать один режим.
Чекбокс без текстового описания ухудшает доступность.
Неправильно:
<Checkbox.Root />
Правильно:
<label>
<Checkbox.Root />
Получать уведомления
</label>
indeterminate не является булевым значением. Его нужно
передавать строкой.
checked="indeterminate"
В крупных приложениях логика групп чекбоксов часто выносится в отдельный компонент:
CheckboxGroup
├ CheckboxItem
├ CheckboxItem
├ CheckboxItem
Пример структуры:
<CheckboxGroup
value={selected}
onCha nge={setSelected}
>
<CheckboxItem value="react" />
<CheckboxItem value="vue" />
</CheckboxGroup>
Такой подход:
Ключевые особенности архитектуры:
Checkbox.Root является базовым строительным
блокомchecked,
unchecked, indeterminate