Checkbox
A control that toggles between checked, unchecked, and indeterminate.
import { Div, Label } from "@implementjs/core";
import { Checkbox } from "@/lib/components/ui/checkbox";
export default function CheckboxDemo() {
return Div(
{ class: "flex flex-col gap-4" },
Div(
{ class: "flex items-center gap-2" },
Checkbox({ id: "terms" }),
Label(
{ for: "terms", class: "text-sm leading-none font-medium" },
"Accept terms and conditions",
),
),
Div(
{ class: "flex items-center gap-2" },
Checkbox({ id: "emails", checked: true }),
Label(
{ for: "emails", class: "text-sm leading-none font-medium" },
"Send me product updates",
),
),
Div(
{ class: "flex items-center gap-2" },
Checkbox({ id: "partial", indeterminate: true }),
Label(
{ for: "partial", class: "text-sm leading-none font-medium" },
"Select all notifications",
),
),
Div(
{ class: "flex items-center gap-2" },
Checkbox({ id: "disabled", checked: true, disabled: true }),
Label(
{
for: "disabled",
class:
"text-sm leading-none font-medium peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
},
"Disabled",
),
),
);
}A checkbox is a button that turns a value on and off. Checkbox renders a Button with role="checkbox" and keeps aria-checked in sync — you give it a size, a border, and the indicator that shows inside it.
import { Checkbox } from "@implementjs/primitives";
Checkbox();
It accepts optional props and children — pass a props object when you need attributes, or pass children directly. See createComponent. Extra props are forwarded onto the underlying Button.
Checked state
checked defaults to false. Pass a boolean to seed it, or a signal to control it from outside (signal() returns a writable unchanged, so the same prop accepts both):
const accepted = signal(false);
Checkbox({ checked: accepted });
Button({ onClick: () => accepted.set(true) }, "Accept");
Clicking the checkbox toggles checked. Space and Enter do the same, because it is a real Button.
Indeterminate
indeterminate is for a parent that represents a mixed set — some children on, some off. Pass a boolean or a signal. While it is true, data-state is "indeterminate" and aria-checked is "mixed".
Clicking an indeterminate checkbox clears that flag and checks it:
const all = signal(false);
const mixed = signal(true);
Checkbox({ checked: all, indeterminate: mixed });
Labels
Pair it with a Label whose for matches the checkbox id. Clicking the text then toggles the control, and the accessible name comes from the label instead of the indicator:
import { Label } from "@implementjs/core";
Div(
{ class: "flex items-center gap-2" },
Checkbox({ id: "terms" }),
Label({ for: "terms" }, "Accept terms and conditions"),
);
Forms
Pass name and the checkbox renders a visually hidden native input that submits with the form. The value is "on" while checked; pass value to change it. required and disabled apply to that input too:
Form(
{ method: "post" },
Checkbox({ name: "terms", value: "accepted" }),
Button({ type: "submit" }, "Continue"),
);
Without name, no hidden input is rendered. An indeterminate checkbox submits as unchecked.
Styling
The primitive is unstyled until you give it a look. It sets data-checkbox-root and data-state as "checked", "unchecked", or "indeterminate", so one class list can cover every state. Children are the indicator — typically a check icon that you show while checked, and a minus while mixed:
import { CheckIcon, MinusIcon } from "@implementjs/lucide";
Checkbox(
{
class:
"size-4 rounded-[4px] border border-input data-[state=checked]:border-primary data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground data-[state=indeterminate]:border-primary data-[state=indeterminate]:bg-primary data-[state=indeterminate]:text-primary-foreground",
},
CheckIcon({ class: "size-3.5 hidden [[data-state=checked]_&]:block" }),
MinusIcon({ class: "size-3.5 hidden [[data-state=indeterminate]_&]:block" }),
);
data-state is there for the fill, the icon, and anything else that should react to checked versus mixed without you threading a signal through.
API Reference
Checkbox
A toggle that is checked, unchecked, or indeterminate. Sets role="checkbox" and aria-checked. Give it a look and an indicator; it handles the state. Renders a Button; extra props are forwarded onto it.
| Prop | Type | Default | Description |
|---|---|---|---|
checked | Signal<boolean> | boolean | false | The checked state. Pass a signal to control it from outside; a boolean seeds uncontrolled state. |
indeterminate | Signal<boolean> | boolean | false | Partial selection. While true, data-state is "indeterminate" and aria-checked is "mixed". A click clears it and checks the box. |
name | string | — | If set, a hidden checkbox is rendered so the value submits with a form. |
value | string | "on" | The value submitted while checked. Only used when name is set. |
required | boolean | false | Marks the hidden input as required. Sets aria-required on the button. |
| Data attribute | Value |
|---|---|
[data-checkbox-root] | Present |
[data-state] | "checked" | "unchecked" | "indeterminate" |