Checkbox Group
Checkbox Groups combine a series of checkboxes together.
'use client';
import * as React from 'react';
import { Checkbox } from '@base_ui/react/Checkbox';
import { CheckboxGroup } from '@base_ui/react/CheckboxGroup';
import { Field } from '@base_ui/react/Field';
export default function UnstyledCheckboxIndeterminateGroup() {
return (
<Field.Root>
<div style={{ display: 'flex', flexDirection: 'column' }}>
<CheckboxGroup.Root defaultValue={['red']}>
<Field.Label className="CheckboxGroup-label">Colors</Field.Label>
<div style={{ display: 'flex', flexDirection: 'column' }}>
<Field.Root>
<Checkbox.Root className="Checkbox" name="red">
<Checkbox.Indicator className="Checkbox-indicator">
<CheckIcon className="Check" />
</Checkbox.Indicator>
</Checkbox.Root>
<Field.Label className="Checkbox-label">Red</Field.Label>
</Field.Root>
<Field.Root>
<Checkbox.Root className="Checkbox" name="green">
<Checkbox.Indicator className="Checkbox-indicator">
<CheckIcon className="Check" />
</Checkbox.Indicator>
</Checkbox.Root>
<Field.Label className="Checkbox-label">Green</Field.Label>
</Field.Root>
<Field.Root>
<Checkbox.Root className="Checkbox" name="blue">
<Checkbox.Indicator className="Checkbox-indicator">
<CheckIcon className="Check" />
</Checkbox.Indicator>
</Checkbox.Root>
<Field.Label className="Checkbox-label">Blue</Field.Label>
</Field.Root>
</div>
</CheckboxGroup.Root>
<Styles />
</div>
</Field.Root>
);
}
const grey = {
100: '#E5EAF2',
300: '#C7D0DD',
500: '#9DA8B7',
600: '#6B7A90',
800: '#303740',
900: '#1C2025',
};
function Styles() {
return (
<style>
{`
.Check {
height: 100%;
width: 100%;
}
.CheckboxGroup-label {
display: flex;
font-weight: bold;
gap: 8px;
margin-bottom: 8px;
font-size: 17px;
}
.Checkbox-label {
display: flex;
font-weight: 500;
gap: 8px;
margin-bottom: 8px;
}
.Checkbox {
all: unset;
box-sizing: border-box;
text-align: center;
width: 24px;
height: 24px;
padding: 0;
border-radius: 4px;
border: 2px solid ${grey[600]};
background: none;
transition-property: background, border-color;
transition-duration: 0.15s;
}
.Checkbox[data-disabled] {
opacity: 0.4;
cursor: not-allowed;
}
.Checkbox:focus-visible {
outline: 2px solid ${grey[500]};
outline-offset: 2px;
}
.Checkbox[data-checked] {
border-color: ${grey[800]};
background: ${grey[800]};
}
.Checkbox-indicator {
height: 100%;
display: inline-block;
visibility: hidden;
color: ${grey[100]};
}
.Checkbox-indicator[data-checked] {
visibility: visible;
}
.Checkbox-icon {
width: 100%;
height: 100%;
}
@media (prefers-color-scheme: dark) {
.Checkbox {
border-color: ${grey[500]};
}
.Checkbox:focus-visible {
outline: 2px solid ${grey[600]};
outline-offset: 2px;
}
.Checkbox[data-checked] {
border-color: ${grey[300]};
background: ${grey[300]};
}
.Checkbox:hover:not([data-disabled]) {
border-color: ${grey[100]};
}
.Checkbox-indicator {
color: ${grey[900]};
}
}
`}
</style>
);
}
function CheckIcon(props: React.SVGProps<SVGSVGElement>) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
{...props}
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
>
<path
d="M9 16.17 4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"
fill="currentColor"
/>
</svg>
);
}
Installation
Base UI components are all available as a single package.
npm install @base_ui/react
Once you have the package installed, import the component.
import { CheckboxGroup } from '@base_ui/react/CheckboxGroup'; import { Checkbox } from '@base_ui/react/Checkbox';
Anatomy
Checkbox Group is composed of a Root
component and Checkbox
components:
<CheckboxGroup.Root />
renders a<div>
with agroup
role.<Checkbox.Root />
renders an individual<button>
checkbox.
Labeling
Field
components are used to label the Checkbox Group and individual Checkboxes:
Controlled
The value
and onValueChange
props control the Checkbox Group with external state. value
is an array of strings matching the name
props of Checkboxes that are currently checked:
Parent Checkbox
A Checkbox can control a group of child Checkboxes.
- Make
CheckboxGroup.Root
controlled and addallValues
as a prop — an array of strings that contains the names of all the child checkboxes. - Add a
parent
prop to theCheckbox.Root
component that controls the other (child) Checkboxes inside the group. - Give the child Checkboxes a
name
prop that identifies them inside theallValues
array.
'use client';
import * as React from 'react';
import { Checkbox as BaseCheckbox } from '@base_ui/react/Checkbox';
import { CheckboxGroup } from '@base_ui/react/CheckboxGroup';
import { Field } from '@base_ui/react/Field';
import { styled } from '@mui/system';
const colors = ['red', 'green', 'blue'];
export default function UnstyledCheckboxGroupNested() {
const [value, setValue] = React.useState<string[]>([]);
return (
<Field.Root style={{ display: 'flex', flexDirection: 'column' }}>
<CheckboxGroup.Root
allValues={colors}
value={value}
onValueChange={setValue}
preserveChildStates={false}
>
<CheckboxGroupLabel>Colors</CheckboxGroupLabel>
<FieldRoot render={<ul />}>
<Checkbox parent>
<Indicator
render={(props, { indeterminate }) => (
<span {...props}>
{indeterminate ? <HorizontalRuleIcon /> : <CheckIcon />}
</span>
)}
/>
</Checkbox>
<CheckboxLabel>All Colors</CheckboxLabel>
</FieldRoot>
<List>
{colors.map((color) => (
<FieldListItem key={color} render={<li />}>
<Checkbox name={color}>
<Indicator>
<CheckIcon />
</Indicator>
</Checkbox>
<CheckboxLabel>{color}</CheckboxLabel>
</FieldListItem>
))}
</List>
</CheckboxGroup.Root>
</Field.Root>
);
}
const blue = {
400: '#3399FF',
600: '#0072E6',
800: '#004C99',
};
const grey = {
100: '#E5EAF2',
400: '#B0B8C4',
800: '#303740',
};
const CheckboxGroupLabel = styled(Field.Label)`
display: block;
font-weight: bold;
font-size: 18px;
margin-bottom: 8px;
`;
const Checkbox = styled(BaseCheckbox.Root)(
({ theme }) => `
width: 24px;
height: 24px;
padding: 0;
border-radius: 4px;
border: 2px solid ${blue[600]};
background: none;
transition-property: background, border-color;
transition-duration: 0.15s;
outline: none;
&[data-disabled] {
opacity: 0.4;
cursor: not-allowed;
}
&:focus-visible {
outline: 2px solid ${theme.palette.mode === 'dark' ? blue[800] : blue[400]};
outline-offset: 2px;
}
&[data-checked], &[data-indeterminate] {
border-color: transparent;
background: ${blue[600]};
}
`,
);
const HorizontalRuleIcon = styled(function HorizontalRuleIcon(
props: React.SVGProps<SVGSVGElement>,
) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
{...props}
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
>
<path d="M4 11h16v2H4z" fill="currentColor" />
</svg>
);
})`
height: 100%;
width: 100%;
`;
const CheckIcon = styled(function CheckIcon(props: React.SVGProps<SVGSVGElement>) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
{...props}
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
>
<path
d="M9 16.17 4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"
fill="currentColor"
/>
</svg>
);
})`
height: 100%;
width: 100%;
`;
const Indicator = styled(BaseCheckbox.Indicator)`
height: 100%;
display: inline-block;
visibility: hidden;
color: ${grey[100]};
&[data-checked],
&[data-indeterminate] {
visibility: visible;
}
`;
const FieldRoot = styled(Field.Root)`
display: flex;
align-items: center;
margin-bottom: 8px;
padding: 0;
`;
const List = styled('ul')`
list-style: none;
padding: 0;
margin: 0;
margin-left: 32px;
`;
const FieldListItem = styled(Field.Root)`
display: flex;
align-items: center;
&:not(:last-child) {
margin-bottom: 8px;
}
`;
const CheckboxLabel = styled(Field.Label)`
display: flex;
gap: 8px;
text-transform: capitalize;
padding-left: 8px;
`;
To preserve the initial state of the child checkboxes when the parent checkbox is toggled, set the preserveChildStates
prop to true
:
API Reference
CheckboxGroupRoot
The foundation for building custom-styled checkbox groups.
Prop | Type | Default | Description |
---|---|---|---|
allValues | arrayOf | All values of the checkboxes in the group. | |
className | union | Class names applied to the element or a function that returns them based on the component's state. | |
defaultValue | arrayOf | The default checked values of the checkbox group. Use when uncontrolled. | |
disabled | bool | false | Whether the checkbox group is disabled. |
onValueChange | func | A callback function that is called when the value of the checkbox group changes. Use when controlled. | |
preserveChildStates | bool | false | Whether the parent checkbox should preserve its child states when checked/unchecked, leading to a tri-state checkbox group. |
render | union | A function to customize rendering of the component. | |
value | arrayOf | The currently checked values of the checkbox group. Use when controlled. |