ComponentsCheckbox
Checkbox
Let users turn individual options on or off.
On this page
Use this component from the local workspace package. Follow the setup guide first. A public npm package and registry are not available yet.
View registry filesImport the component into your page or component file.
import { Checkbox } from "@dethink/components";Try the examples, then open the code to use them in your app.
With Field anatomy
Field, FieldControl, FieldLabel, and FieldDescription wire the label association and description announcement.
An adoption and reliability digest every Monday.
Show sourceexamples/checkbox/basic.tsx
"use client";
import {
Checkbox,
Field,
FieldContent,
FieldControl,
FieldDescription,
FieldLabel,
} from "@dethink/components";
export function CheckboxBasic() {
return (
<div className="mx-auto max-w-sm space-y-4">
<Field id="cb-updates" orientation="horizontal">
<FieldControl asChild>
<Checkbox name="updates" value="yes" defaultChecked />
</FieldControl>
<FieldLabel>Receive product updates</FieldLabel>
</Field>
<Field id="cb-summary" orientation="horizontal">
<FieldControl asChild>
<Checkbox name="summary" value="enabled" />
</FieldControl>
<FieldContent>
<FieldLabel>Weekly summary</FieldLabel>
<FieldDescription>
An adoption and reliability digest every Monday.
</FieldDescription>
</FieldContent>
</Field>
</div>
);
}States and sizes
Checked, indeterminate, disabled, invalid, and the three control sizes.
Show sourceexamples/checkbox/states.tsx
"use client";
import { Checkbox, Field, FieldControl, FieldLabel } from "@dethink/components";
export function CheckboxStates() {
return (
<div className="mx-auto grid max-w-md gap-4 sm:grid-cols-2">
<Field id="cb-checked" orientation="horizontal">
<FieldControl asChild>
<Checkbox defaultChecked />
</FieldControl>
<FieldLabel>Checked</FieldLabel>
</Field>
<Field id="cb-indeterminate" orientation="horizontal">
<FieldControl asChild>
<Checkbox checked="indeterminate" readOnly />
</FieldControl>
<FieldLabel>Indeterminate</FieldLabel>
</Field>
<Field id="cb-disabled" orientation="horizontal">
<FieldControl asChild>
<Checkbox disabled defaultChecked />
</FieldControl>
<FieldLabel>Disabled</FieldLabel>
</Field>
<Field id="cb-invalid" orientation="horizontal">
<FieldControl asChild>
<Checkbox invalid required />
</FieldControl>
<FieldLabel>Invalid, required</FieldLabel>
</Field>
<Field id="cb-sm" orientation="horizontal">
<FieldControl asChild>
<Checkbox controlSize="sm" defaultChecked />
</FieldControl>
<FieldLabel>Small</FieldLabel>
</Field>
<Field id="cb-lg" orientation="horizontal">
<FieldControl asChild>
<Checkbox controlSize="lg" defaultChecked />
</FieldControl>
<FieldLabel>Large</FieldLabel>
</Field>
</div>
);
}Examples that combine components for common tasks.
Permissions tree with tri-state parent
The parent checkbox derives its state from the children — checked, unchecked, or indeterminate — and clicking it snaps the group to the obvious next state. Screen readers announce the mixed state natively.
1 of 4 permissions granted
Show sourceexamples/checkbox/recipe-permissions-tree.tsx
"use client";
import { useState } from "react";
import {
Checkbox,
Field,
FieldControl,
FieldLabel,
type CheckboxCheckedState,
} from "@dethink/components";
const permissions = [
{ id: "read", label: "Read repositories" },
{ id: "write", label: "Write and push" },
{ id: "admin", label: "Manage settings" },
{ id: "billing", label: "View billing" },
];
/**
* Classic tri-state pattern: the parent reflects its children — checked when
* all are, unchecked when none are, and "indeterminate" in between — and
* clicking it snaps the whole group to the obvious next state.
*/
export function CheckboxRecipePermissionsTree() {
const [granted, setGranted] = useState<Set<string>>(new Set(["read"]));
const parentState: CheckboxCheckedState =
granted.size === 0
? false
: granted.size === permissions.length
? true
: "indeterminate";
return (
<div className="mx-auto max-w-sm space-y-3">
<Field id="perm-all" orientation="horizontal">
<FieldControl asChild>
<Checkbox
checked={parentState}
onCheckedChange={() =>
setGranted(
parentState === true
? new Set()
: new Set(permissions.map((permission) => permission.id)),
)
}
/>
</FieldControl>
<FieldLabel className="font-medium">All permissions</FieldLabel>
</Field>
<div className="border-border space-y-3 border-l pl-6">
{permissions.map((permission) => (
<Field
key={permission.id}
id={`perm-${permission.id}`}
orientation="horizontal"
>
<FieldControl asChild>
<Checkbox
checked={granted.has(permission.id)}
onCheckedChange={(checked) =>
setGranted((current) => {
const next = new Set(current);
if (checked === true) {
next.add(permission.id);
} else {
next.delete(permission.id);
}
return next;
})
}
/>
</FieldControl>
<FieldLabel>{permission.label}</FieldLabel>
</Field>
))}
</div>
<p className="text-muted-foreground text-sm">
{granted.size} of {permissions.length} permissions granted
</p>
</div>
);
}Checkbox renders a real input element, so everything a native checkbox accepts works here.
| Prop | What it does | Default |
|---|---|---|
checkedboolean | "indeterminate" | Controlled state. "indeterminate" renders the mixed state and announces as such. | Not set |
defaultCheckedboolean | "indeterminate" | The starting state when the component manages its own state. | false |
onCheckedChange(checked: boolean | "indeterminate") => void | Called with the new state when the user toggles the control. | Not set |
controlSize"sm" | "md" | "lg" | Sets the control size to match other form fields. | "md" |
invalidboolean | Shows an error style and marks the field as invalid for screen readers. | false |
…native input propsInputHTMLAttributes | Renders a real <input type="checkbox">: name, value, disabled, required, readOnly, and form behavior are native. | Not set |