Skip to content

Instantly share code, notes, and snippets.

@alexmkio
Last active November 18, 2025 21:52
Show Gist options
  • Select an option

  • Save alexmkio/0a717f7597b56e499c091db05a8a3c15 to your computer and use it in GitHub Desktop.

Select an option

Save alexmkio/0a717f7597b56e499c091db05a8a3c15 to your computer and use it in GitHub Desktop.
import { useCallback, useId, useMemo } from 'react';
import Checkbox from '@components/Checkbox';
export type CheckboxOption = { value: string; label: string };
type CheckboxesProps = {
name: string;
options: CheckboxOption[];
values: string[];
onChange: (next: string[]) => void;
selectAllLabel?: string;
disabled?: boolean;
};
const Checkboxes = (props: CheckboxesProps) => {
const { name, options, values, onChange, selectAllLabel = 'Select all', disabled = false } = props;
const generatedId = useId();
const allValues = useMemo(() => options?.map((option) => option?.value), [options]);
const allSelected = allValues.length > 0 && allValues.every((value) => values.includes(value));
const someSelected = !allSelected && allValues.some((value) => values.includes(value));
const setAll = useCallback(
(nextChecked: boolean) => {
onChange(nextChecked ? allValues : []);
},
[onChange, allValues],
);
const toggleOne = useCallback(
(id: string, nextChecked: boolean) => {
const next = nextChecked ? Array.from(new Set([...values, id])) : values.filter((value) => value !== id);
onChange(next);
},
[onChange, values],
);
const handleSelectAllChange = useCallback(
(val: boolean | 'indeterminate') => {
setAll(Boolean(val));
},
[setAll],
);
const handleOptionChange = useCallback(
(optionValue: string) => (val: boolean | 'indeterminate') => {
toggleOne(optionValue, !!val);
},
[toggleOne],
);
return (
<>
{selectAllLabel && (
<Checkbox
id={`${generatedId}-all`}
name={`${name}__selectAll`}
label={selectAllLabel}
checked={allSelected ? true : someSelected ? 'indeterminate' : false}
onCheckedChange={handleSelectAllChange}
disabled={disabled}
/>
)}
{options.map((opt) => {
const id = `${generatedId}-${opt.value}`;
const checked = values.includes(opt.value);
return (
<Checkbox
key={opt.value}
id={id}
name={name}
value={opt.value}
label={opt.label}
checked={checked}
onCheckedChange={handleOptionChange(opt.value)}
disabled={disabled}
/>
);
})}
</>
);
};
export default Checkboxes;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment