---
title: Checkbox Group
description: Checkbox groups let users select any number of related options. Use them when choices are independent and more than one can be selected.
---

import { meta as CheckboxGroupMeta, Default } from '@/content/stories/checkbox-group';
import Canvas from '@/components/component-docs/canvas';
import Demo from '@/components/component-docs/demo';

export const config = {
	dependencies: {
		components: [Canvas, Demo],
		scripts: [
			'../../../components/component-docs/demo.script.tsx',
			'../../../components/component-docs/canvas.script.tsx',
			'../../../components/component-docs/controls.script.tsx',
		],
	},
};


# Checkbox Group

<p class="docs-lede">Checkbox groups let users select any number of related options. Use them when choices are independent and more than one can be selected.</p>

## Try it

<Demo of={Default} meta={CheckboxGroupMeta} />

## Usage

The live `value` property is always a `string[]` (`[]` when nothing is selected). The HTML attribute is those tokens as a comma-separated string. JSX may pass a string or an array; a string is parsed as CSV. `rui-change` emits `{ value: string[] }`. Wrap in `RuiField` for form integration. Set `name` on the group (or the field) to list inner checkboxes on native `FormData`.

```tsx
import { RuiCheckbox } from '@ecopages/radiant-ui/checkbox';
import { RuiCheckboxGroup, RuiCheckboxGroupControl } from '@ecopages/radiant-ui/checkbox-group';
import { RuiField } from '@ecopages/radiant-ui/field';
import { RuiLabel } from '@ecopages/radiant-ui/label';

<RuiField name="topics">
  <RuiLabel>Topics</RuiLabel>
  <RuiCheckboxGroup value={['news', 'travel']} name="topics" label="Topics">
    <RuiCheckboxGroupControl>
      <RuiCheckbox value="news">News</RuiCheckbox>
      <RuiCheckbox value="travel">Travel</RuiCheckbox>
    </RuiCheckboxGroupControl>
  </RuiCheckboxGroup>
</RuiField>
```

## Custom markup

`<rui-checkbox-group>` coordinates any light-DOM tree that matches its query contract. The `Rui*` helpers stamp these targets; they are not required.

```tsx
import '@ecopages/radiant-ui/checkbox-group';
import '@ecopages/radiant-ui/checkbox';

<rui-checkbox-group value="news,travel" name="topics" label="Topics">
  <div data-checkbox-group-root role="group" class="rui-checkbox-group">
    <rui-checkbox value="news">News</rui-checkbox>
    <rui-checkbox value="travel">Travel</rui-checkbox>
  </div>
</rui-checkbox-group>
```

BEM classes are presentation-only. Do not set `checked`, `disabled`, or `name` on `rui-checkbox` children — the host owns those.

## Independent choices

<p>Use checkbox groups when users may select multiple related options. For mutually exclusive choices, use a <a href="/docs/forms/radio-group">radio group</a> instead. For a single on/off toggle, use a <a href="/docs/forms/checkbox">checkbox</a>.</p>

## Theming

Checkbox group layout uses the group surface only; checkbox chrome comes from `RuiCheckbox`:

| Part | CSS roles |
| --- | --- |
| Group (`.rui-checkbox-group`) | `gap-inline`; horizontal layout via `data-orientation` |
| Checkbox rows | See [Checkbox](/docs/forms/checkbox) theming |

## API

`RuiCheckboxGroup` is a custom element (`<rui-checkbox-group>`). Compose its options with `RuiCheckboxGroupControl` and `RuiCheckbox`, or use the convenience `options` prop.

### Attributes

| Attribute | Type | Default | Description |
| --- | --- | --- | --- |
| `value` | `string` | omitted | Comma-separated selected tokens. Empty selection removes the attribute. The JS property is `string[]`. |
| `name` | `string` | `''` | Form field name shared by all checkboxes in the group. |
| `label` | `string` | `''` | Accessible name when no visible legend is composed in the view. |
| `disabled` | `boolean` | `false` | Disables every checkbox in the group. |
| `orientation` | `'horizontal' \| 'vertical'` | `'vertical'` | Layout axis for checkbox items. |

### Light-DOM contract

| Target | Required | Host writes | Author owns |
| --- | --- | --- | --- |
| `[data-checkbox-group-root]` | yes | `aria-label`, `aria-disabled`, `data-orientation` | the group node |
| `rui-checkbox` | yes (per option) | `checked`, `disabled`, `name` | `value`, `data-disabled` |

Do not set `checked`, `disabled`, or `name` on checkboxes. Nested hosts: `rui-checkbox`.

### Events

| Event | Detail | Description |
| --- | --- | --- |
| `rui-change` | `{ value: string[] }` | Emitted after the selection changes. |

### Props

| Prop | Type | Description |
| --- | --- | --- |
| `options` | `RuiCheckboxOption[]` | `{ value, label, disabled? }` entries rendered by the view. |
| `value` | `string \| string[]` | Selected tokens. A string is parsed as CSV; the host stores `string[]`. |

### View helpers

| Component | Target stamped | Notes |
| --- | --- | --- |
| `RuiCheckboxGroup` | `<rui-checkbox-group>` | Accepts `options` or children. |
| `RuiCheckboxGroupControl` | `[data-checkbox-group-root]` | `role="group"` container. |
| `RuiCheckbox` | `rui-checkbox` | One per option; see [Checkbox](/docs/forms/checkbox). |

### CSS classes

| Class | Description |
| --- | --- |
| `.rui-checkbox-group` | Group surface (`role="group"`). |

## Accessibility

- The group exposes `role="group"` with an accessible name from `label` or an associated `RuiLabel`.
- Each option is a native checkbox with Space-to-toggle.
- For required multi-select fields, validate through `RuiField` rules rather than per-checkbox `required`.
