Checkbox
A checkbox component supporting controlled, uncontrolled, group and custom indicator
Installation
Usage
Basic Usage
Basic checkbox supporting controlled and uncontrolled modes.
"use client";
import { Checkbox } from "@/ui";
export default function Demo() {
return (
<div className="flex flex-col gap-4">
<Checkbox defaultChecked>Uncontrolled Native</Checkbox>
</div>
);
}
Group Controlled Mode
Data-driven group mode with select-all / indeterminate states.
"use client";
import { useState } from "react";
import { Checkbox } from "@/ui";
import { Check, Minus } from "lucide-react";
export default function Demo() {
const [values, setValues] = useState(["Controlled"]);
const allValues = ["Controlled", "Group", "Custom"];
const allChecked = allValues.every((v) => values.includes(v));
const indeterminate = !allChecked && values.length > 0;
return (
<div className="flex flex-col gap-4">
<Checkbox
checked={values.length > 0}
indicator={indeterminate ? <Minus /> : allChecked ? <Check /> : null}
onClick={() => {
setValues(allChecked ? [] : allValues);
}}
>
All
</Checkbox>
<Checkbox.Group
value={values}
onChange={setValues}
className="pl-4"
options={[
{
label: "Controlled",
value: "Controlled",
indicator: <Check />,
},
{
label: "Group",
value: "Group",
indicator: <Check />,
},
{
label: "Custom-Indicator",
value: "Custom",
indicator: <Check />,
},
]}
/>
</div>
);
}
Custom
Real-focus checkboxes toggle with Space natively; CheckboxRoot also toggles on Enter, so popover-hosted groups (multi-select) can be operated entirely from the keyboard.
Build a select-all group with indeterminate state using the composable components. Note that CheckboxRoot must be nested inside CheckboxIndicator — the focus ring relies on has-focus-visible: matching a descendant of the indicator, so placing the root outside breaks the visible focus style on keyboard focus.
"use client";
import { useState } from "react";
import { CheckboxLabel, CheckboxRoot, CheckboxIndicator } from "@/ui";
import { Check, Minus } from "lucide-react";
const ALL_VALUES = ["Controlled", "Group", "Custom"];
export default function Demo() {
const [values, setValues] = useState<string[]>([]);
const allChecked = ALL_VALUES.every((v) => values.includes(v));
const indeterminate = !allChecked && values.length > 0;
const toggleAll = () => setValues(allChecked ? [] : ALL_VALUES);
const toggleItem = (val: string) =>
setValues((prev) =>
prev.includes(val) ? prev.filter((v) => v !== val) : [...prev, val],
);
return (
<div className="flex flex-col gap-4">
<CheckboxLabel>
<CheckboxIndicator>
<CheckboxRoot checked={values.length > 0} onChange={toggleAll} />
{indeterminate ? <Minus /> : <Check />}
</CheckboxIndicator>
<span>All</span>
</CheckboxLabel>
<div className="flex flex-col gap-2 pl-4">
{ALL_VALUES.map((val) => (
<CheckboxLabel key={val}>
<CheckboxIndicator>
<CheckboxRoot
checked={values.includes(val)}
onChange={() => toggleItem(val)}
/>
<Check />
</CheckboxIndicator>
<span>{val}</span>
</CheckboxLabel>
))}
</div>
</div>
);
}
API Reference
High-level Components
Ready-to-use composite components.
Checkbox
| Prop | Type | Default | Description |
|---|---|---|---|
children | React.ReactNode | - | The checkbox label text |
checked | boolean | - | Controlled checked state |
defaultChecked | boolean | - | Default checked state (uncontrolled) |
onChange | (e: React.ChangeEvent<HTMLInputElement>) => void | - | Native change callback |
onCheckedChange | (checked: boolean) => void | - | Callback when the checked state changes |
indicator | React.ReactNode | - | Custom indicator content, replaces default icon |
className | ClassNameValue | - | Custom classes, applied to the checkbox box |
style | React.CSSProperties | - | Inline styles, applied to the checkbox box |
classNames | { indicator?: ClassNameValue; label?: ClassNameValue } | - | Custom classes for the indicator and label |
styles | { indicator?: React.CSSProperties; label?: React.CSSProperties } | - | Inline styles for the indicator and label |
disabled | boolean | false | Disable the checkbox |
...props | React.ComponentProps<"input"> | - | Supports all native input props (except type, className, value), such as name, value, required |
Checkbox.Group
| Prop | Type | Default | Description |
|---|---|---|---|
options | (CheckboxOptionConfig | CheckboxOptionGroup)[] | - | Options data array, flat or grouped |
value | string[] | - | Controlled selected values |
defaultValue | string[] | [] | Default selected values (uncontrolled) |
onChange | (values: string[]) => void | - | Callback when values change |
name | string | - | Group name, applied to each input |
disabled | boolean | false | Disable all options |
className | ClassNameValue | - | Custom class names, applied to the container |
common | { classNames?: { indicator?: ClassNameValue; label?: ClassNameValue }; styles?: { indicator?: React.CSSProperties; label?: React.CSSProperties }; indicator?: React.ReactNode } | - | Uniform configuration applied to each option |
CheckboxOptionConfig
Extends all Checkbox props except children.
| Field | Type | Default | Description |
|---|---|---|---|
label | string | - | Option display text |
value | string | - | Unique identifier value |
indicator | React.ReactNode | - | Option custom indicator |
CheckboxOptionGroup
Grouped options, rendered as a group with a header.
| Field | Type | Default | Description |
|---|---|---|---|
group | string | - | Group header |
options | CheckboxOptionConfig[] | - | Options within a group |
Composable Components
CheckboxRoot
The visually hidden native input (sr-only) that carries state, focus, and form semantics.
| Prop | Type | Default | Description |
|---|---|---|---|
className | ClassNameValue | - | Custom CSS class |
...props | React.ComponentProps<"input"> | - | Supports all native input props (except type, className, value) |
CheckboxIndicator
The visual indicator rendered as a presentational span; checked styling follows the nested CheckboxRoot via has-checked: automatically, and checkbox semantics come from the input itself.
| Prop | Type | Default | Description |
|---|---|---|---|
className | ClassNameValue | - | Custom CSS class |
children | React.ReactNode | - | Indicator content, defaults to a check icon in the composite |
...props | React.ComponentProps<"span"> | - | Supports all native span props |
CheckboxLabel
The label wrapper that associates the input with the indicator and text.
| Prop | Type | Default | Description |
|---|---|---|---|
className | ClassNameValue | - | Custom CSS class |
...props | React.ComponentProps<"label"> | - | Supports all native label props |