Checkbox Group
Checkbox Groups combine a series of checkboxes together.
Show code '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 >
);
}
Base UI components are all available as a single package.
npm pnpm Yarn
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';
Checkbox Group is composed of a Root
component and Checkbox
components:
<CheckboxGroup.Root />
renders a <div>
with a group
role.
<Checkbox.Root />
renders an individual <button>
checkbox.
< CheckboxGroup.Root >
< Checkbox.Root />
< Checkbox.Root />
</ CheckboxGroup.Root >
Field
components are used to label the Checkbox Group and individual Checkboxes:
import { Field } from '@base_ui/react/Field' ;
< Field.Root >
< CheckboxGroup.Root >
< Field.Label >Colors</ Field.Label >
< Field.Root >
< Checkbox.Root name = "red" />
< Field.Label >Red</ Field.Label >
</ Field.Root >
< Field.Root >
< Checkbox.Root name = "blue" />
< Field.Label >Blue</ Field.Label >
</ Field.Root >
</ CheckboxGroup.Root >
</ Field.Root >
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:
const [ value , setValue ] = useState ([ 'red' ]);
return (
< CheckboxGroup.Root value = { value } onValueChange = { setValue }>
< Checkbox.Root name = "red" /> { /* Checked */ }
< Checkbox.Root name = "green" />
< Checkbox.Root name = "blue" />
</ CheckboxGroup.Root >
);
A Checkbox can control a group of child Checkboxes.
Make CheckboxGroup.Root
controlled and add allValues
as a prop — an array of strings that contains the names of all the child checkboxes.
Add a parent
prop to the Checkbox.Root
component that controls the other (child) Checkboxes inside the group.
Give the child Checkboxes a name
prop that identifies them inside the allValues
array.
const allValues = [ 'a' , 'b' , 'c' ];
function App () {
const [ value , setValue ] = useState ([]);
return (
< CheckboxGroup.Root value = { value } onValueChange = { setValue } allValues = { allValues }>
< Checkbox.Root parent />
{ allValues . map (( value ) => (
< Checkbox.Root key = { value } name = { value } />
))}
</ CheckboxGroup.Root >
);
}
Show code '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
:
< CheckboxGroup.Root preserveChildStates >
< Checkbox.Root parent />
{ allValues . map (( value ) => (
< Checkbox.Root key = { value } name = { value } />
))}
</ CheckboxGroup.Root >
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.