# Checkbox Documentation Allow users to switch between checked, unchecked, and indeterminate states. This is a documentation section that potentially contains examples, demos, and other useful information related to a specific part of Bits UI. When helping users with this documentation, you can ignore the classnames applied to the demos unless they are relevant to the user's issue. ```svelte <script lang="ts"> import { Checkbox, Label } from "bits-ui"; import Check from "phosphor-svelte/lib/Check"; import Minus from "phosphor-svelte/lib/Minus"; </script> <div class="flex items-center space-x-3"> <Checkbox.Root id="terms" aria-labelledby="terms-label" class="border-muted bg-foreground data-[state=unchecked]:border-border-input data-[state=unchecked]:bg-background data-[state=unchecked]:hover:border-dark-40 peer inline-flex size-[25px] items-center justify-center rounded-md border transition-all duration-150 ease-in-out active:scale-[0.98]" name="hello" indeterminate > {#snippet children({ checked, indeterminate })} <div class="text-background inline-flex items-center justify-center"> {#if indeterminate} <Minus class="size-[15px]" weight="bold" /> {:else if checked} <Check class="size-[15px]" weight="bold" /> {/if} </div> {/snippet} </Checkbox.Root> <Label.Root id="terms-label" for="terms" class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" > Accept terms and conditions </Label.Root> </div> ``` ## Overview The Checkbox component provides a flexible and accessible way to create checkbox inputs in your Svelte applications. It supports three states: checked, unchecked, and indeterminate, allowing for complex form interactions and data representations. ## Key Features - **Tri-State Support**: Handles checked, unchecked, and indeterminate states, providing versatility in form design. - **Accessibility**: Built with WAI-ARIA guidelines in mind, ensuring keyboard navigation and screen reader support. - **Flexible State Management**: Supports both controlled and uncontrolled state, allowing for full control over the checkbox's checked state. ## Architecture The Checkbox component is composed of the following parts: - **Root**: The main component that manages the state and behavior of the checkbox. ## Structure Here's an overview of how the Checkbox component is structured in code: ```svelte <script lang="ts"> import { Checkbox } from "bits-ui"; </script> <Checkbox.Root> {#snippet children({ checked, indeterminate })} {#if indeterminate} - {:else if checked} {:else} {/if} {/snippet} </Checkbox.Root> ``` ## Reusable Components It's recommended to use the `Checkbox` primitive to create your own custom checkbox component that can be used throughout your application. In the example below, we're using the `Checkbox` and [`Label`](/docs/components/label) components to create a custom checkbox component. MyCheckbox.svelte ```svelte <script lang="ts"> import { Checkbox, Label, useId, type WithoutChildrenOrChild } from "bits-ui"; let { id = useId(), checked = $bindable(false), ref = $bindable(null), labelRef = $bindable(null), ...restProps }: WithoutChildrenOrChild<Checkbox.RootProps> & { labelText: string; labelRef?: HTMLLabelElement | null; } = $props(); </script> <Checkbox.Root bind:checked bind:ref {...restProps}> {#snippet children({ checked, indeterminate })} {#if indeterminate} - {:else if checked} {:else} {/if} {/snippet} </Checkbox.Root> <Label.Root for={id} bind:ref={labelRef}> {labelText} </Label.Root> ``` You can then use the `MyCheckbox` component in your application like so: +page.svelte ```svelte <script lang="ts"> import MyCheckbox from "$lib/components/MyCheckbox.svelte"; </script> <MyCheckbox labelText="Enable notifications" /> ``` ## Managing Checked State This section covers how to manage the `checked` state of the Checkbox. ### Two-Way Binding Use `bind:checked` for simple, automatic state synchronization: ```svelte <script lang="ts"> import { Checkbox } from "bits-ui"; let myChecked = $state(false); </script> <button onclick={() => (myChecked = false)}> uncheck </button> <Checkbox.Root bind:checked={myChecked} /> ``` ### Fully Controlled Use a [Function Binding](https://svelte.dev/docs/svelte/bind#Function-bindings) for complete control over the state's reads and writes. ```svelte <script lang="ts"> import { Checkbox } from "bits-ui"; let myChecked = $state(false); function getChecked() { return myChecked; } function setChecked(newChecked: boolean) { myChecked = newChecked; } </script> <Checkbox.Root bind:checked={getChecked, setChecked}> </Checkbox.Root> ``` ## Managing Indeterminate State This section covers how to manage the `indeterminate` state of the Checkbox. ### Two-Way Binding Use `bind:indeterminate` for simple, automatic state synchronization: ```svelte <script lang="ts"> import MyCheckbox from "$lib/components/MyCheckbox.svelte"; let myIndeterminate = $state(true); </script> <button onclick={() => (myIndeterminate = false)}> clear indeterminate </button> <MyCheckbox bind:indeterminate={myIndeterminate} /> ``` ### Fully Controlled Use a [Function Binding](https://svelte.dev/docs/svelte/bind#Function-bindings) for complete control over the state's reads and writes. ```svelte <script lang="ts"> import { Checkbox } from "bits-ui"; let myIndeterminate = $state(true); function getIndeterminate() { return myIndeterminate; } function setIndeterminate(newIndeterminate: boolean) { myIndeterminate = newIndeterminate; } </script> <Checkbox.Root bind:indeterminate={getIndeterminate, setIndeterminate}> </Checkbox.Root> ``` ## Disabled State You can disable the checkbox by setting the `disabled` prop to `true`. ```svelte <MyCheckbox disabled labelText="Enable notifications" /> ``` ## HTML Forms If you set the `name` prop, a hidden checkbox input will be rendered to submit the value of the checkbox with a form. By default, the checkbox will be submitted with default checkbox value of `'on'` if the `checked` prop is `true`. ```svelte <MyCheckbox name="notifications" labelText="Enable notifications" /> ``` ### Custom Input Value If you'd prefer to submit a different value, you can use the `value` prop to set the value of the hidden input. For example, if you wanted to submit a string value, you could do the following: ```svelte <MyCheckbox value="hello" name="notifications" labelText="Enable notifications" /> ``` ### Required If you want to make the checkbox required, you can use the `required` prop. ```svelte <Checkbox.Root required> </Checkbox.Root> ``` This will apply the `required` attribute to the hidden input element, ensuring that proper form submission is enforced. ## Checkbox Groups You can use the `Checkbox.Group` component to create a checkbox group. ```svelte <script lang="ts"> import { Checkbox } from "bits-ui"; </script> <Checkbox.Group name="notifications"> <Checkbox.GroupLabel>Notifications</Checkbox.GroupLabel> <Checkbox.Root value="marketing" /> <Checkbox.Root value="promotions" /> <Checkbox.Root value="news" /> </Checkbox.Group> ``` ```svelte <script lang="ts"> import { Checkbox, Label, useId } from "bits-ui"; import Check from "phosphor-svelte/lib/Check"; import Minus from "phosphor-svelte/lib/Minus"; let myValue = $state<string[]>(["marketing", "news"]); </script> <Checkbox.Group class="flex flex-col gap-3" bind:value={myValue} name="notifications" > <Checkbox.GroupLabel class="text-foreground-alt text-sm font-medium"> Notifications </Checkbox.GroupLabel> <div class="flex flex-col gap-4"> {@render MyCheckbox({ label: "Marketing", value: "marketing" })} {@render MyCheckbox({ label: "Promotions", value: "promotions" })} {@render MyCheckbox({ label: "News", value: "news" })} {@render MyCheckbox({ label: "Updates", value: "updates" })} </div> </Checkbox.Group> {#snippet MyCheckbox({ value, label }: { value: string; label: string })} {@const id = useId()} <div class="flex items-center"> <Checkbox.Root {id} aria-labelledby="{id}-label" class="border-muted bg-foreground data-[state=unchecked]:border-border-input data-[state=unchecked]:bg-background data-[state=unchecked]:hover:border-dark-40 peer inline-flex size-[25px] items-center justify-center rounded-md border transition-all duration-150 ease-in-out active:scale-[0.98]" name="hello" {value} > {#snippet children({ checked, indeterminate })} <div class="text-background inline-flex items-center justify-center"> {#if indeterminate} <Minus class="size-[15px]" weight="bold" /> {:else if checked} <Check class="size-[15px]" weight="bold" /> {/if} </div> {/snippet} </Checkbox.Root> <Label.Root id="{id}-label" for={id} class="pl-3 text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" > {label} </Label.Root> </div> {/snippet} ``` ### Managing Value State This section covers how to manage the `value` state of a Checkbox Group. #### Two-Way Binding Use `bind:value` for simple, automatic state synchronization: ```svelte <script lang="ts"> import { Checkbox } from "bits-ui"; let myValue = $state<string[]>([]); </script> <button onclick={() => { myValue = ["item-1", "item-2"]; }} > Open Items 1 and 2 </button> <Checkbox.Group name="myItems" bind:value={myValue}> <Checkbox.GroupLabel>Items</Checkbox.GroupLabel> <Checkbox.Root value="item-1" /> <Checkbox.Root value="item-2" /> <Checkbox.Root value="item-3" /> </Checkbox.Group> ``` #### Fully Controlled Use a [Function Binding](https://svelte.dev/docs/svelte/bind#Function-bindings) for complete control over the state's reads and writes. ```svelte <script lang="ts"> import { Checkbox } from "bits-ui"; let myValue = $state<string[]>([]); function getValue() { return myValue; } function setValue(newValue: string[]) { myValue = newValue; } </script> <Checkbox.Group bind:value={getValue, setValue}> </Checkbox.Group> ``` ### HTML Forms To render hidden `<input />` elements for the various checkboxes within a group, pass a `name` to `Checkbox.Group`. All descendent checkboxes will then render hidden inputs with the same name. ```svelte <Checkbox.Group name="notifications"> </Checkbox.Group> ``` When a `Checkbox.Group` component is used, its descendent `Checkbox.Root` components will use certain properties from the group, such as the `name`, `required`, and `disabled`. ## API Reference ### Checkbox.Root The button component used to toggle the state of the checkbox. | Property | Type | Description | | ---------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `checked` $bindable | `boolean` | The checkbox button's checked state.`Default: false` | | `onCheckedChange` | `function`- (checked: boolean) => void | A callback that is fired when the checkbox button's checked state changes.`Default: undefined` | | `indeterminate` $bindable | `boolean` | Whether the checkbox is an indeterminate state or not.`Default: false` | | `onIndeterminateChange` | `function`- (indeterminate: boolean) => void | A callback that is fired when the indeterminate state changes.`Default: undefined` | | `disabled` | `boolean` | Whether or not the checkbox button is disabled. This prevents the user from interacting with it.`Default: false` | | `required` | `boolean` | Whether or not the checkbox is required.`Default: false` | | `name` | `string` | The name of the checkbox. If provided a hidden input will be render to use for form submission. If not provided, the hidden input will not be rendered.`Default: undefined` | | `value` | `string` | The value of the checkbox. This is what is submitted with the form when the checkbox is checked.`Default: undefined` | | `ref` $bindable | `HTMLButtonElement` | The underlying DOM element being rendered. You can bind to this to get a reference to the element.`Default: undefined` | | `children` | `Snippet`- Snippet | The children content to render.`Default: undefined` | | `child` | `Snippet`- type SnippetProps = { props: Record\<string, unknown>; }; | Use render delegation to render your own element. See [Child Snippet](/docs/child-snippet) docs for more information.`Default: undefined` | | Data Attribute | Value | Description | | ----------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | | `data-state` | `enum`- 'checked' \| 'unchecked' \| 'indeterminate' | The checkbox's state of checked, unchecked, or indeterminate. | | `data-disabled` | `''` | Present when the checkbox is disabled. | | `data-checkbox-root` | `''` | Present on the root element. | ### Checkbox.Group A group that synchronizes its value state with its descendant checkboxes. | Property | Type | Description | | -------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `value` $bindable | `string[]` | The value of the group. This is an array of the values of the checked checkboxes within the group.`Default: []` | | `onValueChange` | `function`- (value: string\[]) => void | A callback that is fired when the checkbox group's value state changes.`Default: undefined` | | `disabled` | `boolean` | Whether or not the checkbox group is disabled. If `true`, all checkboxes within the group will be disabled. To disable a specific checkbox in the group, pass the `disabled` prop to the checkbox.`Default: false` | | `required` | `boolean` | Whether or not the checkbox group is required for form submission.`Default: false` | | `name` | `string` | The name of the checkbox group. If provided a hidden input will be rendered to use for form submission.`Default: undefined` | | `ref` $bindable | `HTMLDivElement` | The underlying DOM element being rendered. You can bind to this to get a reference to the element.`Default: undefined` | | `children` | `Snippet` | The children content to render.`Default: undefined` | | `child` | `Snippet`- type SnippetProps = { props: Record\<string, unknown>; }; | Use render delegation to render your own element. See [Child Snippet](/docs/child-snippet) docs for more information.`Default: undefined` | | Data Attribute | Value | Description | | -------------------------------------------------------------------------------- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | | `data-disabled` | `''` | Present when the checkbox group is disabled. | | `data-checkbox-group` | `''` | Present on the group element. | ### Checkbox.GroupLabel An accessible label for the checkbox group. | Property | Type | Description | | ------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `ref` $bindable | `HTMLLabelElement` | The underlying DOM element being rendered. You can bind to this to get a reference to the element.`Default: undefined` | | `children` | `Snippet` | The children content to render.`Default: undefined` | | `child` | `Snippet`- type SnippetProps = { props: Record\<string, unknown>; }; | Use render delegation to render your own element. See [Child Snippet](/docs/child-snippet) docs for more information.`Default: undefined` | | Data Attribute | Value | Description | | -------------------------------------------------------------------------------- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | | `data-disabled` | `''` | Present when the checkbox group is disabled. | | `data-checkbox-group-label` | `''` | Present on the label element. |