useCheckboxGroup
Provides the behavior and accessibility implementation for a checkbox group component. Checkbox groups allow users to select multiple items from a list of options.
install | yarn add react-aria |
---|---|
version | 3.35.0 |
usage | import {useCheckboxGroup, useCheckboxGroupItem} from 'react-aria' |
API#
useCheckboxGroup(
(props: AriaCheckboxGroupProps,
, state: CheckboxGroupState
)): CheckboxGroupAria
useCheckboxGroupItem(
props: AriaCheckboxGroupItemProps,
state: CheckboxGroupState,
inputRef: RefObject<HTMLInputElement
| | null>
): CheckboxAria
Features#
Checkbox groups can be built in HTML with the
<fieldset>
and <input> elements,
however these can be difficult to style. useCheckboxGroup
and useCheckboxGroupItem
help achieve accessible
checkbox groups that can be styled as needed.
- Checkbox groups are exposed to assistive technology via ARIA
- Each checkbox is built with a native HTML
<input>
element, which can be optionally visually hidden to allow custom styling - Full support for browser features like form autofill and validation
- Keyboard focus management and cross browser normalization
- Group and checkbox labeling support for assistive technology
Anatomy#
A checkbox group consists of a set of checkboxes, and a label. Each checkbox includes a label and a visual selection indicator. Zero or more checkboxes within the group can be selected at a time. Users may click or touch a checkbox to select it, or use the Tab key to navigate to it and the Space key to toggle it.
useCheckboxGroup
returns props for the group and its label, which you should spread
onto the appropriate element:
Name | Type | Description |
groupProps | DOMAttributes | Props for the checkbox group wrapper element. |
labelProps | DOMAttributes | Props for the checkbox group's visible label (if any). |
descriptionProps | DOMAttributes | Props for the checkbox group description element, if any. |
errorMessageProps | DOMAttributes | Props for the checkbox group error message element, if any. |
isInvalid | boolean | Whether the input value is invalid. |
validationErrors | string[] | The current error messages for the input if it is invalid, otherwise an empty array. |
validationDetails | ValidityState | The native validation details for the input. |
useCheckboxGroupItem
returns props for an individual checkbox:
Name | Type | Description |
labelProps | LabelHTMLAttributes<HTMLLabelElement> | Props for the label wrapper element. |
inputProps | InputHTMLAttributes<HTMLInputElement> | Props for the input element. |
isSelected | boolean | Whether the checkbox is selected. |
isPressed | boolean | Whether the checkbox is in a pressed state. |
isDisabled | boolean | Whether the checkbox is disabled. |
isReadOnly | boolean | Whether the checkbox is read only. |
isInvalid | boolean | Whether the input value is invalid. |
validationErrors | string[] | The current error messages for the input if it is invalid, otherwise an empty array. |
validationDetails | ValidityState | The native validation details for the input. |
Selection state is managed by the useCheckboxGroupState
hook in @react-stately/checkbox
. The state object should be passed as an option to useCheckboxGroup
and useCheckboxGroupItem
.
Individual checkboxes must have a visual label. If the checkbox group does not have a visible label,
an aria-label
or aria-labelledby
prop must be passed instead to identify the element to assistive
technology.
Note: useCheckboxGroupItem
should only be used when it is contained within a checkbox group. For a
standalone checkbox, use the useCheckbox hook instead.
Example#
This example uses native input elements for the checkboxes, and React context to share state from the group
to each checkbox. An HTML <label>
element wraps the native input and the text to provide an implicit label
for the checkbox.
import {useCheckboxGroupState} from 'react-stately';
import {useCheckboxGroup, useCheckboxGroupItem} from 'react-aria';
let CheckboxGroupContext = React.createContext(null);
function CheckboxGroup(props) {
let { children, label, description } = props;
let state = useCheckboxGroupState(props);
let {
groupProps,
labelProps,
descriptionProps,
errorMessageProps,
isInvalid,
validationErrors
} = useCheckboxGroup(props, state);
return (
<div {...groupProps}>
<span {...labelProps}>{label}</span>
<CheckboxGroupContext.Provider value={state}>
{children}
</CheckboxGroupContext.Provider>
{description && (
<div {...descriptionProps} style={{ fontSize: 12 }}>{description}</div>
)}
{isInvalid &&
(
<div {...errorMessageProps} style={{ color: 'red', fontSize: 12 }}>
{validationErrors.join(' ')}
</div>
)}
</div>
);
}
function Checkbox(props) {
let { children } = props;
let state = React.useContext(CheckboxGroupContext);
let ref = React.useRef(null);
let { inputProps } = useCheckboxGroupItem(props, state, ref);
let isDisabled = state.isDisabled || props.isDisabled;
let isSelected = state.isSelected(props.value);
return (
<label
style={{
display: 'block',
color: (isDisabled && 'var(--gray)') || (isSelected && 'var(--blue)')
}}
>
<input {...inputProps} ref={ref} />
{children}
</label>
);
}
<CheckboxGroup label="Favorite sports">
<Checkbox value="soccer" isDisabled>Soccer</Checkbox>
<Checkbox value="baseball">Baseball</Checkbox>
<Checkbox value="basketball">Basketball</Checkbox>
</CheckboxGroup>
import {useCheckboxGroupState} from 'react-stately';
import {
useCheckboxGroup,
useCheckboxGroupItem
} from 'react-aria';
let CheckboxGroupContext = React.createContext(null);
function CheckboxGroup(props) {
let { children, label, description } = props;
let state = useCheckboxGroupState(props);
let {
groupProps,
labelProps,
descriptionProps,
errorMessageProps,
isInvalid,
validationErrors
} = useCheckboxGroup(props, state);
return (
<div {...groupProps}>
<span {...labelProps}>{label}</span>
<CheckboxGroupContext.Provider value={state}>
{children}
</CheckboxGroupContext.Provider>
{description && (
<div {...descriptionProps} style={{ fontSize: 12 }}>
{description}
</div>
)}
{isInvalid &&
(
<div
{...errorMessageProps}
style={{ color: 'red', fontSize: 12 }}
>
{validationErrors.join(' ')}
</div>
)}
</div>
);
}
function Checkbox(props) {
let { children } = props;
let state = React.useContext(CheckboxGroupContext);
let ref = React.useRef(null);
let { inputProps } = useCheckboxGroupItem(
props,
state,
ref
);
let isDisabled = state.isDisabled || props.isDisabled;
let isSelected = state.isSelected(props.value);
return (
<label
style={{
display: 'block',
color: (isDisabled && 'var(--gray)') ||
(isSelected && 'var(--blue)')
}}
>
<input {...inputProps} ref={ref} />
{children}
</label>
);
}
<CheckboxGroup label="Favorite sports">
<Checkbox value="soccer" isDisabled>Soccer</Checkbox>
<Checkbox value="baseball">Baseball</Checkbox>
<Checkbox value="basketball">Basketball</Checkbox>
</CheckboxGroup>
import {useCheckboxGroupState} from 'react-stately';
import {
useCheckboxGroup,
useCheckboxGroupItem
} from 'react-aria';
let CheckboxGroupContext =
React.createContext(
null
);
function CheckboxGroup(
props
) {
let {
children,
label,
description
} = props;
let state =
useCheckboxGroupState(
props
);
let {
groupProps,
labelProps,
descriptionProps,
errorMessageProps,
isInvalid,
validationErrors
} = useCheckboxGroup(
props,
state
);
return (
<div {...groupProps}>
<span
{...labelProps}
>
{label}
</span>
<CheckboxGroupContext.Provider
value={state}
>
{children}
</CheckboxGroupContext.Provider>
{description && (
<div
{...descriptionProps}
style={{
fontSize: 12
}}
>
{description}
</div>
)}
{isInvalid &&
(
<div
{...errorMessageProps}
style={{
color:
'red',
fontSize:
12
}}
>
{validationErrors
.join(' ')}
</div>
)}
</div>
);
}
function Checkbox(
props
) {
let { children } =
props;
let state = React
.useContext(
CheckboxGroupContext
);
let ref = React.useRef(
null
);
let { inputProps } =
useCheckboxGroupItem(
props,
state,
ref
);
let isDisabled =
state.isDisabled ||
props.isDisabled;
let isSelected = state
.isSelected(
props.value
);
return (
<label
style={{
display: 'block',
color:
(isDisabled &&
'var(--gray)') ||
(isSelected &&
'var(--blue)')
}}
>
<input
{...inputProps}
ref={ref}
/>
{children}
</label>
);
}
<CheckboxGroup label="Favorite sports">
<Checkbox
value="soccer"
isDisabled
>
Soccer
</Checkbox>
<Checkbox value="baseball">
Baseball
</Checkbox>
<Checkbox value="basketball">
Basketball
</Checkbox>
</CheckboxGroup>
Styling#
See the useCheckbox docs for details on how to customize the styling of checkbox elements.
Styled examples#
Usage#
The following examples show how to use the CheckboxGroup
component created in the above example.
Default value#
An initial, uncontrolled value can be provided to the CheckboxGroup using the defaultValue
prop, which accepts an array of selected items that map to the
value
prop on each Checkbox.
<CheckboxGroup
label="Favorite sports (uncontrolled)"
defaultValue={['soccer', 'baseball']}
>
<Checkbox value="soccer">Soccer</Checkbox>
<Checkbox value="baseball">Baseball</Checkbox>
<Checkbox value="basketball">Basketball</Checkbox>
</CheckboxGroup>
<CheckboxGroup
label="Favorite sports (uncontrolled)"
defaultValue={['soccer', 'baseball']}
>
<Checkbox value="soccer">Soccer</Checkbox>
<Checkbox value="baseball">Baseball</Checkbox>
<Checkbox value="basketball">Basketball</Checkbox>
</CheckboxGroup>
<CheckboxGroup
label="Favorite sports (uncontrolled)"
defaultValue={[
'soccer',
'baseball'
]}
>
<Checkbox value="soccer">
Soccer
</Checkbox>
<Checkbox value="baseball">
Baseball
</Checkbox>
<Checkbox value="basketball">
Basketball
</Checkbox>
</CheckboxGroup>
Controlled value#
A controlled value can be provided using the value
prop, which accepts an array of selected items, which map to the
value
prop on each Checkbox. The onChange
event is fired when the user checks or unchecks an option. It receives a new array
containing the updated selected values.
function Example() {
let [selected, setSelected] = React.useState(['soccer', 'baseball']);
return (
<CheckboxGroup
label="Favorite sports (controlled)"
value={selected}
onChange={setSelected}
>
<Checkbox value="soccer">Soccer</Checkbox>
<Checkbox value="baseball">Baseball</Checkbox>
<Checkbox value="basketball">Basketball</Checkbox>
</CheckboxGroup>
);
}
function Example() {
let [selected, setSelected] = React.useState([
'soccer',
'baseball'
]);
return (
<CheckboxGroup
label="Favorite sports (controlled)"
value={selected}
onChange={setSelected}
>
<Checkbox value="soccer">Soccer</Checkbox>
<Checkbox value="baseball">Baseball</Checkbox>
<Checkbox value="basketball">Basketball</Checkbox>
</CheckboxGroup>
);
}
function Example() {
let [
selected,
setSelected
] = React.useState([
'soccer',
'baseball'
]);
return (
<CheckboxGroup
label="Favorite sports (controlled)"
value={selected}
onChange={setSelected}
>
<Checkbox value="soccer">
Soccer
</Checkbox>
<Checkbox value="baseball">
Baseball
</Checkbox>
<Checkbox value="basketball">
Basketball
</Checkbox>
</CheckboxGroup>
);
}
Description#
The description
prop can be used to associate additional help text with a checkbox group.
<CheckboxGroup
label="Favorite sports"
description="Select your favorite sports."
>
<Checkbox value="soccer">Soccer</Checkbox>
<Checkbox value="baseball">Baseball</Checkbox>
<Checkbox value="basketball">Basketball</Checkbox>
</CheckboxGroup>
<CheckboxGroup
label="Favorite sports"
description="Select your favorite sports."
>
<Checkbox value="soccer">Soccer</Checkbox>
<Checkbox value="baseball">Baseball</Checkbox>
<Checkbox value="basketball">Basketball</Checkbox>
</CheckboxGroup>
<CheckboxGroup
label="Favorite sports"
description="Select your favorite sports."
>
<Checkbox value="soccer">
Soccer
</Checkbox>
<Checkbox value="baseball">
Baseball
</Checkbox>
<Checkbox value="basketball">
Basketball
</Checkbox>
</CheckboxGroup>
Group validation#
CheckboxGroup supports the isRequired
prop to ensure the user selects at least one item, as well as custom client and server-side validation. Individual checkboxes also support validation, and errors from all checkboxes are aggregated at the group level. CheckboxGroup can also be integrated with other form libraries. See the Forms guide to learn more.
When a CheckboxGroup has the validationBehavior="native"
prop, validation errors block form submission. The isRequired
prop at the CheckboxGroup
level requires that at least one item is selected. To display validation errors, use the validationErrors
and errorMessageProps
returned by useCheckboxGroup
. This allows you to render error messages from all of the above sources with consistent custom styles.
<form>
<CheckboxGroup
label="Sandwich condiments"
name="condiments"
isRequired
validationBehavior="native" >
<Checkbox value="lettuce">Lettuce</Checkbox>
<Checkbox value="tomato">Tomato</Checkbox>
<Checkbox value="onion">Onion</Checkbox>
<Checkbox value="sprouts">Sprouts</Checkbox>
</CheckboxGroup>
<input type="submit" style={{marginTop: 8}} />
</form>
<form>
<CheckboxGroup
label="Sandwich condiments"
name="condiments"
isRequired
validationBehavior="native" >
<Checkbox value="lettuce">Lettuce</Checkbox>
<Checkbox value="tomato">Tomato</Checkbox>
<Checkbox value="onion">Onion</Checkbox>
<Checkbox value="sprouts">Sprouts</Checkbox>
</CheckboxGroup>
<input type="submit" style={{marginTop: 8}} />
</form>
<form>
<CheckboxGroup
label="Sandwich condiments"
name="condiments"
isRequired
validationBehavior="native" >
<Checkbox value="lettuce">
Lettuce
</Checkbox>
<Checkbox value="tomato">
Tomato
</Checkbox>
<Checkbox value="onion">
Onion
</Checkbox>
<Checkbox value="sprouts">
Sprouts
</Checkbox>
</CheckboxGroup>
<input
type="submit"
style={{
marginTop: 8
}}
/>
</form>
Individual Checkbox validation#
To require that specific checkboxes are checked, set the isRequired
prop at the Checkbox
level instead of the CheckboxGroup
. The following example shows how to require that all items are selected.
<form>
<CheckboxGroup label="Agree to the following" validationBehavior="native">
<Checkbox value="terms" isRequired>Terms and conditions</Checkbox>
<Checkbox value="privacy" isRequired>Privacy policy</Checkbox>
<Checkbox value="cookies" isRequired>Cookie policy</Checkbox> </CheckboxGroup>
<input type="submit" style={{marginTop: 8}} />
</form>
<form>
<CheckboxGroup
label="Agree to the following"
validationBehavior="native"
>
<Checkbox value="terms" isRequired>
Terms and conditions
</Checkbox>
<Checkbox value="privacy" isRequired>
Privacy policy
</Checkbox>
<Checkbox value="cookies" isRequired>
Cookie policy
</Checkbox> </CheckboxGroup>
<input type="submit" style={{ marginTop: 8 }} />
</form>
<form>
<CheckboxGroup
label="Agree to the following"
validationBehavior="native"
>
<Checkbox
value="terms"
isRequired
>
Terms and
conditions
</Checkbox>
<Checkbox
value="privacy"
isRequired
>
Privacy policy
</Checkbox>
<Checkbox
value="cookies"
isRequired
>
Cookie policy
</Checkbox> </CheckboxGroup>
<input
type="submit"
style={{
marginTop: 8
}}
/>
</form>
Disabled#
The entire CheckboxGroup can be disabled with the isDisabled
prop.
<CheckboxGroup label="Favorite sports" isDisabled>
<Checkbox value="soccer">Soccer</Checkbox>
<Checkbox value="baseball">Baseball</Checkbox>
<Checkbox value="basketball">Basketball</Checkbox>
</CheckboxGroup>
<CheckboxGroup label="Favorite sports" isDisabled>
<Checkbox value="soccer">Soccer</Checkbox>
<Checkbox value="baseball">Baseball</Checkbox>
<Checkbox value="basketball">Basketball</Checkbox>
</CheckboxGroup>
<CheckboxGroup
label="Favorite sports"
isDisabled
>
<Checkbox value="soccer">
Soccer
</Checkbox>
<Checkbox value="baseball">
Baseball
</Checkbox>
<Checkbox value="basketball">
Basketball
</Checkbox>
</CheckboxGroup>
To disable an individual checkbox, pass isDisabled
to the Checkbox
instead.
<CheckboxGroup label="Favorite sports">
<Checkbox value="soccer">Soccer</Checkbox>
<Checkbox value="baseball" isDisabled>Baseball</Checkbox>
<Checkbox value="basketball">Basketball</Checkbox>
</CheckboxGroup>
<CheckboxGroup label="Favorite sports">
<Checkbox value="soccer">Soccer</Checkbox>
<Checkbox value="baseball" isDisabled>Baseball</Checkbox>
<Checkbox value="basketball">Basketball</Checkbox>
</CheckboxGroup>
<CheckboxGroup label="Favorite sports">
<Checkbox value="soccer">
Soccer
</Checkbox>
<Checkbox
value="baseball"
isDisabled
>
Baseball
</Checkbox>
<Checkbox value="basketball">
Basketball
</Checkbox>
</CheckboxGroup>
Read only#
The isReadOnly
prop makes the selection immutable. Unlike isDisabled
, the CheckboxGroup remains focusable.
See the MDN docs for more information.
<CheckboxGroup label="Favorite sports" defaultValue={['baseball']} isReadOnly>
<Checkbox value="soccer">Soccer</Checkbox>
<Checkbox value="baseball">Baseball</Checkbox>
<Checkbox value="basketball">Basketball</Checkbox>
</CheckboxGroup>
<CheckboxGroup
label="Favorite sports"
defaultValue={['baseball']}
isReadOnly
>
<Checkbox value="soccer">Soccer</Checkbox>
<Checkbox value="baseball">Baseball</Checkbox>
<Checkbox value="basketball">Basketball</Checkbox>
</CheckboxGroup>
<CheckboxGroup
label="Favorite sports"
defaultValue={[
'baseball'
]}
isReadOnly
>
<Checkbox value="soccer">
Soccer
</Checkbox>
<Checkbox value="baseball">
Baseball
</Checkbox>
<Checkbox value="basketball">
Basketball
</Checkbox>
</CheckboxGroup>
HTML forms#
CheckboxGroup supports the name
prop, paired with the Checkbox value
prop, for integration with HTML forms.
<CheckboxGroup label="Favorite sports" name="sports">
<Checkbox value="soccer">Soccer</Checkbox>
<Checkbox value="baseball">Baseball</Checkbox>
<Checkbox value="basketball">Basketball</Checkbox>
</CheckboxGroup>
<CheckboxGroup label="Favorite sports" name="sports">
<Checkbox value="soccer">Soccer</Checkbox>
<Checkbox value="baseball">Baseball</Checkbox>
<Checkbox value="basketball">Basketball</Checkbox>
</CheckboxGroup>
<CheckboxGroup
label="Favorite sports"
name="sports"
>
<Checkbox value="soccer">
Soccer
</Checkbox>
<Checkbox value="baseball">
Baseball
</Checkbox>
<Checkbox value="basketball">
Basketball
</Checkbox>
</CheckboxGroup>