Controlled group of checkboxes backed by an array value. Renders a labeled form wrapper containing one CheckboxInput per option; the value is the list of selected option ids.
Use @uxf/ui/checkbox-list to let the user pick multiple options from a fixed list, tracking the selection as an array of ids.
@uxf/form form: use @uxf/form/checkbox-list instead — it registers the field with react-hook-form. Reach for the ui component for a standalone, controlled list.CheckboxInput.import { CheckboxList } from "@uxf/ui/checkbox-list";
import { useState } from "react";
const OPTIONS = [
{ id: "1", label: "Option 1" },
{ id: "2", label: "Option 2" },
{ id: "3", label: "Option 3" },
];
function Example() {
const [values, setValues] = useState<string[] | null>([]);
return <CheckboxList label="Pick options" name="options" onChange={setValues} options={OPTIONS} value={values} />;
}
CheckboxList is generic over the option id type: CheckboxList<ValueId extends string | number, Option>. ValueId is inferred from options. Props extend FormControlProps<ValueId[] | null>.
| Prop | Type | Default | Description |
|---|---|---|---|
value | ValueId[] | null | — | Required. Ids of the currently selected options. |
onChange | (value: ValueId[] | null, event?, ...args) => void | — | Required. Called with the next selection when an option is toggled, in canonical (sorted) order. |
name | string | — | Required. Field name (shared by all options). |
options | Option[] | — | Required. Options to render (see below). |
label | ReactNode | — | Required. Group label. |
helperText | ReactNode | — | Helper/error text for the group. |
hasHiddenLabel | boolean | false | Visually hides the group label (kept for screen readers). |
isDisabled | boolean | false | Disables the whole group. |
isReadOnly | boolean | false | Read-only state for the group. |
isInvalid | boolean | false | Error state. |
isRequired | boolean | false | Marks the group required. |
id | string | — | Base id (an id is generated with useId when omitted). |
className | string | — | Extra class names on the wrapper. |
onBlur and onFocus (inherited from FormControlProps) are forwarded to each option.
| Field | Type | Description |
|---|---|---|
id | ValueId (number | string) | Required. Unique option id, stored in value. |
label | ReactNode | Required. Option label. |
isDisabled | boolean | Disables just this option (also disabled when the whole group is). |
Exported types: CheckboxListProps, CheckboxListOption, CheckboxListValueId (= number | string).
Note: the group label uses
hasHiddenLabel, nothiddenLabelas onCheckboxInput.
The value is semantically a set, and the emitted array is always sorted by id
(normalizeSelectableIds) rather than kept in click order.
Rendering is unaffected — the list renders from options, never from the value order.
This matters for react-hook-form: it compares arrays index by index, so a click-ordered value made a form
read as dirty after an option was unticked and ticked again. The component can only canonicalize what it
emits, so run your defaultValues through the same helper:
const formApi = useForm<FormData>({ defaultValues: { tags: normalizeSelectableIds(data.tagIds) } });
If you submit this value somewhere order-sensitive, note that the payload order changed.
Reflected via classes on the wrapper: isDisabled, isReadOnly, isInvalid, isRequired.
Import the component stylesheet once in your global CSS. It renders CheckboxInput (which in turn renders Checkbox), so those stylesheets are required too:
@import url("@uxf/ui/css/checkbox-list.css");
@import url("@uxf/ui/css/checkbox-input.css");
@import url("@uxf/ui/css/checkbox.css");
Also requires the global @uxf/ui token layer, set up once per app — see @uxf/ui setup.