motif svelteArc

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.

Live specimen

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.

Installation

pnpm dlx shadcn-svelte@latest add @arcui/checkbox

Usage

<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

PropTypeDefaultDescription
checkedboolean | 'indeterminate'—Controlled state. Use bind:checked for two-way reactivity with Svelte 5 runes.
defaultCheckedboolean | 'indeterminate'falseInitial state when uncontrolled.
onCheckedChange(checked: CheckedState) => void—Callback fired on every toggle transition.
labelstring—Visible label text rendered beside the box; connects automatically as the accessible label.
descriptionstring—Secondary descriptive text rendered under the label, linked via aria-describedby.
disabledbooleanfalseDisables user interaction and dims visual contrast.
requiredbooleanfalseMarks the input field as required in HTML forms.
namestring—Form input field name; renders a hidden input for native form submissions.
valuestring'on'Form value submitted when the checkbox is checked.
idstring—Unique identifier for the input; falls back to an auto-generated id.
refHTMLElement | null—Bindable ref to the underlying Bits UI root button element.

Keyboard Interactions

KeyAction
SpaceToggles the checkbox between checked and unchecked.
TabMoves 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