Browse docs
Browse docs
A binary choice. Backed by Radix UI's checkbox primitive — keyboard navigation, ARIA attributes, and the indeterminate state come for free.
import { Checkbox } from '@dashforge/tw';
<Checkbox label="I agree to the terms" />Standalone:
const [agreed, setAgreed] = useState(false);
<Checkbox
label="I agree to the terms"
checked={agreed}
onCheckedChange={setAgreed}
/>Inside a form:
import { DashForm } from '@dashforge/forms';
import { Checkbox, Button } from '@dashforge/tw';
<DashForm onSubmit={subscribe}>
<Checkbox name="newsletter" label="Subscribe to the weekly digest" />
<Checkbox name="terms" label="I accept the terms of service" required />
<Button type="submit" color="primary">Subscribe</Button>
</DashForm>The bridge registers the boolean automatically — no Controller wrap.
import { Checkbox, Stack } from '@dashforge/tw';
<Stack gap={2}>
<Checkbox name="terms" label="I accept the terms and conditions" />
<Checkbox name="newsletter" label="Send me the monthly newsletter" defaultChecked />
</Stack><Checkbox
label="Send weekly digest"
helper="A Monday morning summary of activity in your workspace."
/>Helper text is rendered below the label in a muted color. Keep it short — one sentence — so the row stays scannable in a settings list.
{/* Uncontrolled — internal state */}
<Checkbox label="Auto-save" defaultChecked />
{/* Controlled — you own the state */}
<Checkbox label="Auto-save" checked={autoSave} onCheckedChange={setAutoSave} />onCheckedChange is the Radix-style callback — receives the next boolean directly (no synthetic event). Use onChange if you need the underlying input event.
const [checked, setChecked] = useState<boolean | 'indeterminate'>('indeterminate');
<Checkbox
label="Select all"
checked={checked}
onCheckedChange={setChecked}
/>Pass the literal string 'indeterminate' as the checked value (or set it via state) to render the dash glyph. Useful for "select all" patterns where some children are selected.
import { Checkbox, Stack } from '@dashforge/tw';
<Stack gap={2}>
<Checkbox name="state-unchecked" label="Unchecked" />
<Checkbox name="state-checked" label="Checked" defaultChecked />
<Checkbox name="state-disabled" label="Disabled" disabled />
<Checkbox name="state-disabled-checked" label="Disabled + checked" disabled defaultChecked />
</Stack><Checkbox label="Premium feature" disabled helper="Upgrade your plan to enable." />Disabled checkboxes are removed from tab order and rendered at reduced opacity. The label is also dimmed for visual coherence.
You must accept the terms to continue.
import { Checkbox } from '@dashforge/tw';
<Checkbox
name="terms-required"
label="I accept the terms and conditions"
error
helperText="You must accept the terms to continue."
/>When error is set, the checkbox renders with the danger ring and the helper text turns red — same convention as TextField.
<Checkbox
name="adminFlag"
label="Mark as VIP"
access={{ requires: 'workspace.admin', when: 'denied:hide' }}
/>Three when modes ('denied:hide' | 'denied:disable' | 'denied:readonly') — same semantics as Button and TextField.
The classic three-row settings panel:
<div className="space-y-2">
<Checkbox name="emailNotifs" label="Email notifications"
helper="Weekly activity digest." defaultChecked />
<Checkbox name="pushNotifs" label="Push notifications"
helper="Real-time alerts in your browser." />
<Checkbox name="smsNotifs" label="SMS notifications"
helper="Critical security alerts only." />
</div>| Prop | Type | Default | Description |
|---|---|---|---|
name | string | — | Field name. Registers with <DashForm> if present. |
label | ReactNode | — | Inline label rendered next to the checkbox. |
helper | ReactNode | — | Helper text below the label. |
checked | boolean | 'indeterminate' | — | Controlled checked state. |
defaultChecked | boolean | false | Initial checked state when uncontrolled. |
onCheckedChange | (next: boolean | 'indeterminate') => void | — | Radix-style callback. |
disabled | boolean | false | Disables and dims the row. |
required | boolean | false | Marks as required for <DashForm> validation. |
access | AccessSpec | — | RBAC gating. |
slotProps | { root?, indicator?, label?, helper? } | — | Per-slot overrides. |
className | string | — | Merged onto root via tailwind-merge. |
| ...rest | Radix Checkbox.Root props | — | All Radix props pass through. |
root (wrapping <label>) · box (the visible check container) · indicator (the check / dash glyph) · label · helper
@radix-ui/react-checkbox) — the accessibility primitives are not hand-rolled. Indeterminate state, focus management, and keyboard handling are Radix's responsibility, not ours.<input type="checkbox"> — it's a styled <button role="checkbox">. A real hidden <input> is present for form serialization compatibility (browsers POST the value when a <form> is submitted natively).<input type="hidden"> if you need to persist the indeterminate semantics.