As we know, checkbox inputs can only have two states: checked or unchecked. They can have any value, but they either submit that value (checked) or don’t (unchecked) with a form submission. The default is unchecked.
Visually, however, there are actually three states a checkbox can be in: checked, unchecked, or indeterminate. Note that the indeterminate state is visual only, so the checkbox is still either checked or unchecked as a state.
So why would you need to use indeterminate? For nested checkboxes. Each checkbox may have child checkboxes. If all those children are checked, it may be checked. If none are checked, it is unchecked. If some of them are checked, then it’s in an indeterminate state (in this case symbolically meaning “partially” checked).
import { Checkbox, Container, Stack } from '@krakentech/coral';
import { useEffect, useMemo, useState } from 'react';
const animals = useMemo(
() => [
{
id: 'elephant',
label: 'Elephant',
},
{
id: 'lion',
label: 'Lion',
},
{
id: 'octopus',
label: 'Octopus',
},
],
[]
);
const [isCheckAll, setIsCheckAll] = useState(false);
const [isCheck, setIsCheck] = useState<string[]>([]);
const handleSelectAll = () => {
setIsCheckAll(!isCheckAll);
setIsCheck(animals.map((item) => item.id));
if (isCheckAll) {
setIsCheck([]);
}
};
const handleChange = (e: any) => {
const { id, checked } = e.target;
setIsCheck([...isCheck, id]);
if (!checked) {
setIsCheck(isCheck.filter((item) => item !== id));
}
};
useEffect(() => {
if (isCheck.length === animals.length) {
setIsCheckAll(true);
} else {
setIsCheckAll(false);
}
}, [isCheck, animals]);
<Stack direction="vertical" alignItems="flex-start" gap="xs">
<Checkbox
name="animals"
label="Animals"
checked={isCheckAll}
indeterminate={!isCheckAll && isCheck.length > 0}
onChange={handleSelectAll}
/>
<Container paddingLeft="mdLg">
<Stack direction="vertical" gap="xxs">
{animals.map((item, index) => (
<span key={index}>
<Checkbox
name={item.id}
id={item.id}
label={item.label}
checked={isCheck.includes(item.id)}
onChange={handleChange}
/>
</span>
))}
</Stack>
</Container>
</Stack>