# Checkbox Group (/components/forms/checkbox-group)

Use `CheckboxGroup` when someone can choose more than one option from a related set. It provides a
shared label, description, and validation message for its `CheckboxField` children.

apps/docs/src/examples/checkbox-group/basic.tsx

```tsx
import { CheckboxField } from '@luke-ui/react/checkbox-field';
import { CheckboxGroup } from '@luke-ui/react/checkbox-group';

export default () => {
	return (
		<CheckboxGroup description="Choose any days that apply." label="Days available">
			<CheckboxField label="Monday" value="monday" />
			<CheckboxField label="Tuesday" value="tuesday" />
			<CheckboxField label="Wednesday" value="wednesday" />
		</CheckboxGroup>
	);
};
```

## Selection [#selection]

Pass `defaultValue` to set the initial selection, or pass `value` with `onChange` to control it.
Pass a unique `value` to each `CheckboxField`. The group value is an array of the selected values.

apps/docs/src/examples/checkbox-group/controlled.tsx

```tsx
import { CheckboxField } from '@luke-ui/react/checkbox-field';
import { CheckboxGroup } from '@luke-ui/react/checkbox-group';
import { Stack } from '@luke-ui/react/stack';
import { Text } from '@luke-ui/react/text';
import { useState } from 'react';

export default () => {
	const [days, setDays] = useState(['monday']);

	return (
		<Stack gap="space.16">
			<CheckboxGroup label="Days available" onChange={setDays} value={days}>
				<CheckboxField label="Monday" value="monday" />
				<CheckboxField label="Tuesday" value="tuesday" />
				<CheckboxField label="Wednesday" value="wednesday" />
			</CheckboxGroup>
			<Text color="secondary" elementType="p" role="status">
				{`Days selected: ${days.length}`}
			</Text>
		</Stack>
	);
};
```

## Layout [#layout]

The group is vertical by default. Set `orientation="horizontal"` to arrange options in a row that
wraps when it runs out of space.

apps/docs/src/examples/checkbox-group/layout.tsx

```tsx
import { CheckboxField } from '@luke-ui/react/checkbox-field';
import { CheckboxGroup } from '@luke-ui/react/checkbox-group';
import { Comparison, ComparisonItem } from '#docs';

export default () => {
	return (
		<Comparison>
			<ComparisonItem label="Vertical">
				<CheckboxGroup label="Days available">
					<CheckboxField label="Monday" value="monday" />
					<CheckboxField label="Tuesday" value="tuesday" />
					<CheckboxField label="Wednesday" value="wednesday" />
				</CheckboxGroup>
			</ComparisonItem>
			<ComparisonItem label="Horizontal">
				<CheckboxGroup label="Days available" orientation="horizontal">
					<CheckboxField label="Monday" value="monday" />
					<CheckboxField label="Tuesday" value="tuesday" />
					<CheckboxField label="Wednesday" value="wednesday" />
				</CheckboxGroup>
			</ComparisonItem>
		</Comparison>
	);
};
```

## Size [#size]

Set `size` to provide a default size for its checkbox fields. A child's `size` takes precedence over
the group size. When neither sets a size, the group inherits `Form.controlSize` or uses `medium`.
The size changes the control without changing the label typography.

apps/docs/src/examples/checkbox-group/sizes.tsx

```tsx
import { CheckboxField } from '@luke-ui/react/checkbox-field';
import { CheckboxGroup } from '@luke-ui/react/checkbox-group';
import { Comparison, ComparisonItem } from '#docs';

export default () => {
	return (
		<Comparison>
			<ComparisonItem label="Small">
				<CheckboxGroup label="Days available" size="small">
					<CheckboxField label="Monday" value="monday" />
					<CheckboxField label="Tuesday" value="tuesday" />
				</CheckboxGroup>
			</ComparisonItem>
			<ComparisonItem label="Medium">
				<CheckboxGroup label="Days available" size="medium">
					<CheckboxField label="Monday" value="monday" />
					<CheckboxField label="Tuesday" value="tuesday" />
				</CheckboxGroup>
			</ComparisonItem>
			<ComparisonItem label="Small group with a medium option">
				<CheckboxGroup label="Days available" size="small">
					<CheckboxField label="Monday" value="monday" />
					<CheckboxField label="Tuesday" size="medium" value="tuesday" />
				</CheckboxGroup>
			</ComparisonItem>
		</Comparison>
	);
};
```

## Validation [#validation]

Set `isRequired` to require at least one selection, or pass `validate` to check the selected values.
Set `isRequired` or pass `validate` on a `CheckboxField` when that option needs its own rule. The
group shows these native validation messages below its options.

Pass `errorMessage` to `CheckboxGroup` for a controlled error from a form library or server. A
non-empty message marks the group invalid and takes precedence over native validation messages. The
description stays visible while the group is invalid. Read [Validation](/docs/validation) for where
messages come from and how to write them.

By default, a required group shows a marker after its label. Read
[Required fields](/docs/forms#required-fields) for the `necessityIndicator` values.

Submit without selecting a day to see the validation message.

apps/docs/src/examples/checkbox-group/validation.tsx

```tsx
import { Button } from '@luke-ui/react/button';
import { CheckboxField } from '@luke-ui/react/checkbox-field';
import { CheckboxGroup } from '@luke-ui/react/checkbox-group';
import { Stack } from '@luke-ui/react/stack';
import type { SubmitEvent } from 'react';

function handleSubmit(event: SubmitEvent<HTMLFormElement>) {
	event.preventDefault();
}

export default () => {
	return (
		<form onSubmit={handleSubmit}>
			<Stack gap="space.16">
				<CheckboxGroup
					description="Choose at least one day."
					isRequired
					label="Days available"
					name="days"
				>
					<CheckboxField label="Monday" value="monday" />
					<CheckboxField label="Tuesday" value="tuesday" />
					<CheckboxField label="Wednesday" value="wednesday" />
				</CheckboxGroup>
				<Button type="submit">Submit</Button>
			</Stack>
		</form>
	);
};
```

Select email updates and submit without accepting the terms to see the group error for the required
option.

apps/docs/src/examples/checkbox-group/required-option.tsx

```tsx
import { Button } from '@luke-ui/react/button';
import { CheckboxField } from '@luke-ui/react/checkbox-field';
import { CheckboxGroup } from '@luke-ui/react/checkbox-group';
import { Stack } from '@luke-ui/react/stack';
import type { SubmitEvent } from 'react';

function handleSubmit(event: SubmitEvent<HTMLFormElement>) {
	event.preventDefault();
}

export default () => {
	return (
		<form onSubmit={handleSubmit}>
			<Stack gap="space.16">
				<CheckboxGroup label="Consent" name="consent">
					<CheckboxField isRequired label="I accept the terms" value="terms" />
					<CheckboxField label="Email me updates" value="updates" />
				</CheckboxGroup>
				<Button type="submit">Submit</Button>
			</Stack>
		</form>
	);
};
```

## Form values [#form-values]

Pass `name` to include the selected values in form submission. Pass `form` to associate the group
with a `<form>` it does not sit inside.

## Accessibility [#accessibility]

Use a visible `label` to name the group. When another part of the layout names it, pass
`aria-labelledby`. Pass `aria-label` when there is no visible group label. Each `CheckboxField`
keeps its own visible label and optional description.

Set `isDisabled` on the group to disable every option. An individual option cannot override a
disabled group with `isDisabled={false}`.

## API [#api]

### CheckboxGroupProps

Props for `CheckboxGroup`.

`CheckboxGroupProps` also accepts compatible DOM and ARIA attributes and event handlers for its rendered element.

| Prop                  | Type                                                                | Description                                                                                                                                                                                                                               |
| --------------------- | ------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `validate?`           | `(value: string[]) => true \| ValidationError \| null \| undefined` | A function that returns an error message if a given value is invalid. Validation errors are displayed to the user when the form is submitted if `validationBehavior="native"`. For realtime validation, use the `isInvalid` prop instead. |
| `defaultValue?`       | `string[]`                                                          | The default value (uncontrolled).                                                                                                                                                                                                         |
| `aria-describedby?`   | `string`                                                            | Identifies the element (or elements) that describes the object.                                                                                                                                                                           |
| `aria-details?`       | `string`                                                            | Identifies the element (or elements) that provide a detailed, extended description for the object.                                                                                                                                        |
| `aria-errormessage?`  | `string`                                                            | Identifies the element that provides an error message for the object.                                                                                                                                                                     |
| `onFocus?`            | `(e: React.FocusEvent<Element, Element>) => void`                   | Handler that is called when the element receives focus.                                                                                                                                                                                   |
| `onBlur?`             | `(e: React.FocusEvent<Element, Element>) => void`                   | Handler that is called when the element loses focus.                                                                                                                                                                                      |
| `onFocusChange?`      | `(isFocused: boolean) => void`                                      | Handler that is called when the element's focus status changes.                                                                                                                                                                           |
| `slot?`               | `string \| null`                                                    | A slot name for the component. Slots allow the component to receive props from a parent component. An explicit `null` value indicates that the local props completely override all props received from a parent.                          |
| `validationBehavior?` | `'native' \| 'aria'`                                                | Whether to use native HTML form validation to prevent form submission when the value is missing or invalid, or mark the field as required or invalid via ARIA. Default: `'native'`                                                        |
| `label?`              | `Exclude<ReactNode, boolean \| null \| undefined>`                  | Visible label. Pass non-empty, textual, non-interactive content. Place links and buttons outside it, and associate external label content with `aria-labelledby` instead.                                                                 |
| `aria-label?`         | `string`                                                            |                                                                                                                                                                                                                                           |
| `aria-labelledby?`    | `string`                                                            |                                                                                                                                                                                                                                           |
| `children`            | `ReactNode`                                                         | Options and their supporting text.                                                                                                                                                                                                        |
| `className?`          | `ClassNameOrFunction<CheckboxGroupRenderProps> \| undefined`        | Class name for the group element.                                                                                                                                                                                                         |
| `description?`        | `ReactNode`                                                         | Supporting text shown below the group label. Optional helper text shown below the control.                                                                                                                                                |
| `errorMessage?`       | `ReactNode`                                                         | Validation message for a controlled error. A non-empty message marks the group invalid.                                                                                                                                                   |
| `form?`               | `string \| undefined`                                               | The form element to associate the group's checkboxes with, by id.                                                                                                                                                                         |
| `id?`                 | `string`                                                            | Element id for the group element.                                                                                                                                                                                                         |
| `isDisabled?`         | `boolean \| undefined`                                              | Whether the entire group is disabled.                                                                                                                                                                                                     |
| `isRequired?`         | `boolean \| undefined`                                              | Whether at least one option must be selected.                                                                                                                                                                                             |
| `name?`               | `string \| undefined`                                               | Name submitted with the selected checkbox values.                                                                                                                                                                                         |
| `onChange?`           | `((value: string[]) => void) \| undefined`                          | Called when the selected options change.                                                                                                                                                                                                  |
| `orientation?`        | `'vertical' \| 'horizontal'`                                        | Controls whether options stack or wrap in rows. Default: `'vertical'`                                                                                                                                                                     |
| `ref?`                | `Ref<HTMLDivElement>`                                               | Ref forwarded to the group element.                                                                                                                                                                                                       |
| `size?`               | `ControlSize`                                                       | Default control size for its options. An option's explicit size takes precedence.                                                                                                                                                         |
| `necessityIndicator?` | `NecessityIndicator`                                                | Controls how the group label identifies required or optional values. Controls how the label identifies required or optional values. Inherits from `Form`, or uses `'required-asterisk'` when unset.                                       |
| `value?`              | `string[] \| undefined`                                             | Selected options (controlled).                                                                                                                                                                                                            |

#### Type definitions

These are the types that this table's signatures and the definitions below name. TypeScript's built-in types, such as `Omit` and `ReadonlyArray`, are not listed.

##### `ControlSize`

```ts
type ControlSize = 'small' | 'medium';
```

##### `NecessityIndicator`

```ts
type NecessityIndicator = 'required-asterisk'
  | 'required-label'
  | 'optional-label';
```

##### `ValidationError`

Declared in [`@react-types/shared`](https://www.npmjs.com/package/@react-types/shared) (`src/inputs.d.ts`).

```ts
type ValidationError = string | string[];
```

##### `FocusEvent`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).

##### `ReactNode`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).

```ts
type ReactNode = ReactElement
  | string
  | number
  | bigint
  | Iterable<ReactNode>
  | ReactPortal
  | boolean
  | null
  | undefined
  | DO_NOT_USE_OR_YOU_WILL_BE_FIRED_EXPERIMENTAL_REACT_NODES[keyof DO_NOT_USE_OR_YOU_WILL_BE_FIRED_EXPERIMENTAL_REACT_NODES]
  | Promise<AwaitedReactNode>;
```

Refers to `ReactElement`, `ReactPortal`, `DO_NOT_USE_OR_YOU_WILL_BE_FIRED_EXPERIMENTAL_REACT_NODES`, and `AwaitedReactNode`.

##### `ReactElement`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).

##### `ReactPortal`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).

##### `DO_NOT_USE_OR_YOU_WILL_BE_FIRED_EXPERIMENTAL_REACT_NODES`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).

##### `AwaitedReactNode`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).

##### `ClassNameOrFunction`

Declared in [`react-aria-components`](https://www.npmjs.com/package/react-aria-components) (`dist/types/src/utils.d.ts`).

```ts
type ClassNameOrFunction<T> = string | ((values: T & {
  defaultClassName: string | undefined;
}) => string);
```

##### `CheckboxGroupRenderProps`

Declared in [`react-aria-components`](https://www.npmjs.com/package/react-aria-components) (`dist/types/src/Checkbox.d.ts`).

##### `Ref`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).

```ts
type Ref<T> = RefCallback<T>
  | RefObject<T | null>
  | null;
```

Refers to `RefCallback` and `RefObject`.

##### `RefCallback`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).

##### `RefObject`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).
