Checkbox ported
A binary choice with a precise, legible state.
A binary or tri-state control with a spring-animated check mark that morphs into an indeterminate dash, and integrated label and description.
Loading demo…
Guidance
When to use
- Independent on and off choices confirmed by a submit button, such as accepting terms and conditions.
- Parent rows that show a partial selection through the indeterminate state.
- Form lists where multiple items can be checked simultaneously.
When not to use
- Use Switch for settings that apply immediately without a form submission.
- Use Radio Group when only one option can be chosen from a visible set.
- Use Chip Group for filter facets people toggle frequently.
pnpm dlx shadcn-svelte@latest add @arcui/checkboxUsage
<script lang="ts">
import Checkbox from '$lib/components/checkbox/checkbox.svelte';
import type { CheckedState } from '$lib/components/checkbox/checkbox.types';
let accepted = $state<CheckedState>(false);
</script>
<Checkbox
bind:checked={accepted}
label="I agree to the terms"
description="You can export your data at any time."
/>Variants & Examples
Controlled with Description
Two-way binding via bind:checked with supporting secondary copy.
<Checkbox bind:checked={accepted} label="Accept terms" description="You can change this later." />Indeterminate State
Displays a horizontal dash mark when partially selected in hierarchical lists.
<Checkbox checked="indeterminate" label="Select all subtasks" />Disabled State
Prevents user interaction and dims visual contrast.
<Checkbox checked={true} label="Required permission" disabled />Uncontrolled with Default
Initializes state once via defaultChecked without external variable binding.
<Checkbox defaultChecked={true} label="Remember me on this device" />API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
checked | boolean | 'indeterminate' | — | Controlled state. Use bind:checked for two-way reactivity with Svelte 5 runes. |
defaultChecked | boolean | 'indeterminate' | false | Initial state when uncontrolled. |
onCheckedChange | (checked: CheckedState) => void | — | Callback fired on every toggle transition. |
label | string | — | Visible label text rendered beside the box; connects automatically as the accessible label. |
description | string | — | Secondary descriptive text rendered under the label, linked via aria-describedby. |
disabled | boolean | false | Disables user interaction and dims visual contrast. |
required | boolean | false | Marks the input field as required in HTML forms. |
name | string | — | Form input field name; renders a hidden input for native form submissions. |
value | string | 'on' | Form value submitted when the checkbox is checked. |
id | string | — | Unique identifier for the input; falls back to an auto-generated id. |
ref | HTMLElement | null | — | Bindable ref to the underlying Bits UI root button element. |
Keyboard Interactions
| Key | Action |
|---|---|
Space | Toggles the checkbox between checked and unchecked. |
Tab | Moves focus to or away from the checkbox control. |
Accessibility
- Bits UI renders a semantic <button> with role="checkbox" and aria-checked (including "mixed" when indeterminate).
- The label is a semantic <label> element tied by id; description is automatically linked via aria-describedby.
- The drawn SVG check mark and fill are aria-hidden="true".
- High-contrast focus ring conforms to WCAG 2.1 AA specifications.
- Full hit area is an expanded touch target (control height) so it remains effortless to tap on mobile even though the visual mark is compact.
Motion
Phase 1 still-state: the fill and check mark render their static end values (opacity 0 vs 1, scale 0.6 vs 1, path d) with no animation. Phase 2 wires the snappy spring fill scale and the check path morphing into the dash path via @humanspeak/svelte-motion. The prefers-reduced-motion path applies every state change instantly via CSS.
Notes for AI
- Use for independent on/off choices in forms. Use Switch for settings that apply immediately upon toggle.
- Set checked="indeterminate" on a parent checkbox when only a subset of child options are selected.
- Bits UI renders a hidden native input when name is set, so it submits with standard HTML forms and SvelteKit form actions.
- Always prefer bind:checked with Svelte 5 runes for reactive two-way binding.
Source of truth: registry/components/checkbox/checkbox.tsx