Checkbox
A control element that allows for multiple selections within a set.
Anatomy
To set up the checkbox correctly, you'll need to understand its anatomy and how we name its parts.
Each part includes a
data-partattribute to help identify them in the DOM.
Design impact on the asChild property
The Checkbox.Root element of the checkbox is a label element. This is because the checkbox is a
form control and should be associated with a label to provide context and meaning to the user.
Otherwise, the HTML and accessibility structure will be invalid.
If you need to use the
asChildproperty, make sure that thelabelelement is the direct child of theCheckbox.Rootcomponent.
Examples
Learn how to use the Checkbox component in your project. Let's take a look at the most basic
example:
import { CheckIcon } from 'lucide-react'
import { Checkbox } from '@ark-ui/react'
export const Basic = () => (
  <Checkbox.Root>
    <Checkbox.Label>Checkbox</Checkbox.Label>
    <Checkbox.Control>
      <Checkbox.Indicator>
        <CheckIcon />
      </Checkbox.Indicator>
    </Checkbox.Control>
    <Checkbox.HiddenInput />
  </Checkbox.Root>
)
import { CheckIcon } from 'lucide-solid'
import { Checkbox } from '@ark-ui/solid'
export const Basic = () => (
  <Checkbox.Root>
    <Checkbox.Label>Checkbox</Checkbox.Label>
    <Checkbox.Control>
      <Checkbox.Indicator>
        <CheckIcon />
      </Checkbox.Indicator>
    </Checkbox.Control>
    <Checkbox.HiddenInput />
  </Checkbox.Root>
)
<script setup lang="ts">
import { Checkbox } from '@ark-ui/vue'
import { CheckIcon } from 'lucide-vue-next'
</script>
<template>
  <Checkbox.Root>
    <Checkbox.Label>Checkbox</Checkbox.Label>
    <Checkbox.Control>
      <Checkbox.Indicator>
        <CheckIcon />
      </Checkbox.Indicator>
    </Checkbox.Control>
    <Checkbox.HiddenInput />
  </Checkbox.Root>
</template>
Controlled Checkbox
To create a controlled Checkbox component, manage the state of the checked status using the
checked prop and update it when the onCheckedChange event handler is called:
import { CheckIcon } from 'lucide-react'
import { useState } from 'react'
import { Checkbox } from '@ark-ui/react'
export const Controlled = () => {
  const [checked, setChecked] = useState<Checkbox.CheckedState>(true)
  return (
    <Checkbox.Root checked={checked} onCheckedChange={(e) => setChecked(e.checked)}>
      <Checkbox.Label>Checkbox</Checkbox.Label>
      <Checkbox.Control>
        <Checkbox.Indicator>
          <CheckIcon />
        </Checkbox.Indicator>
      </Checkbox.Control>
      <Checkbox.HiddenInput />
    </Checkbox.Root>
  )
}
import { CheckIcon } from 'lucide-solid'
import { createSignal } from 'solid-js'
import { Checkbox } from '@ark-ui/solid'
export const Controlled = () => {
  const [checked, setChecked] = createSignal<Checkbox.CheckedState>(true)
  return (
    <Checkbox.Root checked={checked()} onCheckedChange={(e) => setChecked(e.checked)}>
      <Checkbox.Label>Checkbox</Checkbox.Label>
      <Checkbox.Control>
        <Checkbox.Indicator>
          <CheckIcon />
        </Checkbox.Indicator>
      </Checkbox.Control>
      <Checkbox.HiddenInput />
    </Checkbox.Root>
  )
}
<script setup lang="ts">
import { ref } from 'vue'
import { Checkbox, type CheckboxCheckedState } from '@ark-ui/vue'
import { CheckIcon } from 'lucide-vue-next'
const checked = ref<CheckboxCheckedState>(true)
</script>
<template>
  <Checkbox.Root v-model:checked="checked">
    <Checkbox.Label>Checkbox</Checkbox.Label>
    <Checkbox.Control>
      <Checkbox.Indicator>
        <CheckIcon />
      </Checkbox.Indicator>
    </Checkbox.Control>
    <Checkbox.HiddenInput />
  </Checkbox.Root>
</template>
Indeterminate Checkbox
In some cases, you may need a checkbox to represent a state that is neither checked nor unchecked,
known as the indeterminate state. This can be achieved by setting the checked prop to
indeterminate:
import { CheckIcon, MinusIcon } from 'lucide-react'
import { Checkbox } from '@ark-ui/react'
export const Indeterminate = () => (
  <Checkbox.Root checked="indeterminate">
    <Checkbox.Label>Checkbox</Checkbox.Label>
    <Checkbox.Control>
      <Checkbox.Indicator>
        <CheckIcon />
      </Checkbox.Indicator>
      <Checkbox.Indicator indeterminate>
        <MinusIcon />
      </Checkbox.Indicator>
    </Checkbox.Control>
    <Checkbox.HiddenInput />
  </Checkbox.Root>
)
import { CheckIcon, MinusIcon } from 'lucide-solid'
import { Checkbox } from '@ark-ui/solid'
export const Indeterminate = () => (
  <Checkbox.Root checked="indeterminate">
    <Checkbox.Label>Checkbox</Checkbox.Label>
    <Checkbox.Control>
      <Checkbox.Indicator>
        <CheckIcon />
      </Checkbox.Indicator>
      <Checkbox.Indicator indeterminate>
        <MinusIcon />
      </Checkbox.Indicator>
    </Checkbox.Control>
    <Checkbox.HiddenInput />
  </Checkbox.Root>
)
<script setup lang="ts">
import { Checkbox } from '@ark-ui/vue'
import { CheckIcon, MinusIcon } from 'lucide-vue-next'
</script>
<template>
  <Checkbox.Root checked="indeterminate">
    <Checkbox.Label>Checkbox</Checkbox.Label>
    <Checkbox.Control>
      <Checkbox.Indicator>
        <CheckIcon />
      </Checkbox.Indicator>
      <Checkbox.Indicator indeterminate>
        <MinusIcon />
      </Checkbox.Indicator>
    </Checkbox.Control>
    <Checkbox.HiddenInput />
  </Checkbox.Root>
</template>
Checkbox Group
Ark provides a Checkbox.Group component to manage a group of checkboxes. The Checkbox.Group
component manages the state of the checkboxes and provides a way to access the checked values:
import { CheckIcon } from 'lucide-react'
import { Checkbox } from '@ark-ui/react'
const items = [
  { label: 'React', value: 'react' },
  { label: 'Solid', value: 'solid' },
  { label: 'Vue', value: 'vue' },
]
export const Group = () => (
  <Checkbox.Group defaultValue={['react']} onValueChange={console.log}>
    {items.map((item) => (
      <Checkbox.Root value={item.value} key={item.value}>
        <Checkbox.Label>{item.label}</Checkbox.Label>
        <Checkbox.Control>
          <Checkbox.Indicator>
            <CheckIcon />
          </Checkbox.Indicator>
        </Checkbox.Control>
        <Checkbox.HiddenInput />
      </Checkbox.Root>
    ))}
  </Checkbox.Group>
)
import { CheckIcon } from 'lucide-solid'
import { For } from 'solid-js'
import { Checkbox, CheckboxGroup } from '@ark-ui/solid'
const items = [
  { label: 'React', value: 'react' },
  { label: 'Solid', value: 'solid' },
  { label: 'Vue', value: 'vue' },
]
export const Group = () => (
  <CheckboxGroup defaultValue={['react']} onValueChange={console.log}>
    <For each={items}>
      {(item) => (
        <Checkbox.Root value={item.value}>
          <Checkbox.Label>{item.label}</Checkbox.Label>
          <Checkbox.Control>
            <Checkbox.Indicator>
              <CheckIcon />
            </Checkbox.Indicator>
          </Checkbox.Control>
          <Checkbox.HiddenInput />
        </Checkbox.Root>
      )}
    </For>
  </CheckboxGroup>
)
<script setup lang="ts">
import { Checkbox } from '@ark-ui/vue'
import { CheckIcon } from 'lucide-vue-next'
const items = [
  { label: 'React', value: 'react' },
  { label: 'Solid', value: 'solid' },
  { label: 'Vue', value: 'vue' },
]
</script>
<template>
  <Checkbox.Group :defaultValue="['react']" @valueChange="console.log">
    <Checkbox.Root v-for="item in items" :value="item.value" :key="item.value">
      <Checkbox.Label>{{ item.label }}</Checkbox.Label>
      <Checkbox.Control>
        <Checkbox.Indicator>
          <CheckIcon />
        </Checkbox.Indicator>
      </Checkbox.Control>
      <Checkbox.HiddenInput />
    </Checkbox.Root>
  </Checkbox.Group>
</template>
Render Prop Usage
For cases where you need more flexibility in rendering, the Checkbox component offers the use of a render prop. The render prop function gives you access to the checkbox's API, allowing you to customize the checkbox control's rendering:
import { CheckIcon } from 'lucide-react'
import { Checkbox } from '@ark-ui/react'
export const RenderProp = () => (
  <Checkbox.Root>
    <Checkbox.Control>
      <Checkbox.Indicator>
        <CheckIcon />
      </Checkbox.Indicator>
    </Checkbox.Control>
    <Checkbox.Context>
      {(checkbox) => <Checkbox.Label>Checkbox {checkbox.checked.toString()}</Checkbox.Label>}
    </Checkbox.Context>
    <Checkbox.HiddenInput />
  </Checkbox.Root>
)
import { CheckIcon } from 'lucide-solid'
import { Checkbox } from '@ark-ui/solid'
export const RenderProp = () => (
  <Checkbox.Root>
    <Checkbox.Control>
      <Checkbox.Indicator>
        <CheckIcon />
      </Checkbox.Indicator>
    </Checkbox.Control>
    <Checkbox.Context>
      {(checkbox) => <Checkbox.Label>Checkbox {checkbox().checked.toString()}</Checkbox.Label>}
    </Checkbox.Context>
    <Checkbox.HiddenInput />
  </Checkbox.Root>
)
<script setup lang="ts">
import { Checkbox } from '@ark-ui/vue'
import { CheckIcon } from 'lucide-vue-next'
</script>
<template>
  <Checkbox.Root>
    <Checkbox.Control>
      <Checkbox.Indicator>
        <CheckIcon />
      </Checkbox.Indicator>
    </Checkbox.Control>
    <Checkbox.Context v-slot="checkbox">
      <Checkbox.Label>Checkbox {{ checkbox.checked.toString() }}</Checkbox.Label>
    </Checkbox.Context>
    <Checkbox.HiddenInput />
  </Checkbox.Root>
</template>
API Reference
Root
| Prop | Default | Type | 
|---|---|---|
| asChild | booleanRender as a different element type. | |
| checked | CheckedStateThe checked state of the checkbox | |
| defaultChecked | CheckedStateThe checked state of the checkbox when it is first rendered. Use this when you do not need to control the state of the checkbox. | |
| disabled | booleanWhether the checkbox is disabled | |
| form | stringThe id of the form that the checkbox belongs to. | |
| id | stringThe unique identifier of the machine. | |
| ids | Partial<{
  root: string
  hiddenInput: string
  control: string
  label: string
}>The ids of the elements in the checkbox. Useful for composition. | |
| invalid | booleanWhether the checkbox is invalid | |
| name | stringThe name of the input field in a checkbox. Useful for form submission. | |
| onCheckedChange | (details: CheckedChangeDetails) => voidThe callback invoked when the checked state changes. | |
| readOnly | booleanWhether the checkbox is read-only | |
| required | booleanWhether the checkbox is required | |
| value | 'on' | stringThe value of checkbox input. Useful for form submission. | 
| Data Attribute | Value | 
|---|---|
| [data-active] | Present when active or pressed | 
| [data-focus] | Present when focused | 
| [data-readonly] | Present when read-only | 
| [data-hover] | Present when hovered | 
| [data-disabled] | Present when disabled | 
| [data-state] | "indeterminate" | "checked" | "unchecked" | 
| [data-invalid] | Present when invalid | 
Control
| Prop | Default | Type | 
|---|---|---|
| asChild | booleanRender as a different element type. | 
| Data Attribute | Value | 
|---|---|
| [data-active] | Present when active or pressed | 
| [data-focus] | Present when focused | 
| [data-readonly] | Present when read-only | 
| [data-hover] | Present when hovered | 
| [data-disabled] | Present when disabled | 
| [data-state] | "indeterminate" | "checked" | "unchecked" | 
| [data-invalid] | Present when invalid | 
Group
| Prop | Default | Type | 
|---|---|---|
| asChild | booleanRender as a different element type. | |
| defaultValue | string[]The initial value of `value` when uncontrolled | |
| disabled | booleanIf `true`, the checkbox group is disabled | |
| onValueChange | (value: string[]) => voidThe callback to call when the value changes | |
| readOnly | booleanIf `true`, the checkbox group is read-only | |
| value | string[]The controlled value of the checkbox group | 
HiddenInput
| Prop | Default | Type | 
|---|---|---|
| asChild | booleanRender as a different element type. | 
Indicator
| Prop | Default | Type | 
|---|---|---|
| asChild | booleanRender as a different element type. | |
| indeterminate | boolean | 
| Data Attribute | Value | 
|---|---|
| [data-active] | Present when active or pressed | 
| [data-focus] | Present when focused | 
| [data-readonly] | Present when read-only | 
| [data-hover] | Present when hovered | 
| [data-disabled] | Present when disabled | 
| [data-state] | "indeterminate" | "checked" | "unchecked" | 
| [data-invalid] | Present when invalid | 
Label
| Prop | Default | Type | 
|---|---|---|
| asChild | booleanRender as a different element type. | 
| Data Attribute | Value | 
|---|---|
| [data-active] | Present when active or pressed | 
| [data-focus] | Present when focused | 
| [data-readonly] | Present when read-only | 
| [data-hover] | Present when hovered | 
| [data-disabled] | Present when disabled | 
| [data-state] | "indeterminate" | "checked" | "unchecked" | 
| [data-invalid] | Present when invalid | 
RootProvider
| Prop | Default | Type | 
|---|---|---|
| value | UseCheckboxReturn | |
| asChild | booleanRender as a different element type. | 
Accessibility
Complies with the Checkbox WAI-ARIA design pattern.
Keyboard Support
| Key | Description | 
|---|---|
| Space | Toggle the checkbox |