Checkbox
A control element that allows for multiple selections within a set.
You can explore the checkbox component in the following curated examples.
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-part
attribute 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
asChild
property, make sure that thelabel
element is the direct child of theCheckbox.Root
component.
Examples
Learn how to use the Checkbox
component in your project. Let's take a look at the most basic example:
import { Checkbox } from '@ark-ui/react/checkbox'
import { CheckIcon } from 'lucide-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 { Checkbox } from '@ark-ui/solid/checkbox'
import { CheckIcon } from 'lucide-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/checkbox'
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
Use the checked
and onCheckedChange
props to programatically control the checkbox's state.
import { Checkbox } from '@ark-ui/react/checkbox'
import { CheckIcon } from 'lucide-react'
import { useState } from '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 { Checkbox } from '@ark-ui/solid/checkbox'
import { CheckIcon } from 'lucide-solid'
import { createSignal } from 'solid-js'
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 { Checkbox, type CheckboxCheckedState } from '@ark-ui/vue/checkbox'
import { CheckIcon } from 'lucide-vue-next'
import { ref } from 'vue'
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
Use the indeterminate
prop to create a checkbox in an indeterminate state (partially checked).
import { Checkbox } from '@ark-ui/react/checkbox'
import { CheckIcon, MinusIcon } from 'lucide-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 { Checkbox } from '@ark-ui/solid/checkbox'
import { CheckIcon, MinusIcon } from 'lucide-solid'
export const Indeterminate = () => (
<Checkbox.Root defaultChecked="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/checkbox'
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 { Checkbox } from '@ark-ui/react/checkbox'
import { CheckIcon } from 'lucide-react'
const items = [
{ label: 'React', value: 'react' },
{ label: 'Solid', value: 'solid' },
{ label: 'Vue', value: 'vue' },
]
export const Group = () => (
<Checkbox.Group defaultValue={['react']} name="framework" 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 { Checkbox } from '@ark-ui/solid/checkbox'
import { CheckIcon } from 'lucide-solid'
import { For } from 'solid-js'
const items = [
{ label: 'React', value: 'react' },
{ label: 'Solid', value: 'solid' },
{ label: 'Vue', value: 'vue' },
]
export const Group = () => (
<Checkbox.Group defaultValue={['react']} name="framework" 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>
</Checkbox.Group>
)
<script setup lang="ts">
import { Checkbox } from '@ark-ui/vue/checkbox'
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']" name="framework" @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>
Access Checkbox state
Use the Checkbox.Context
and its render prop to access the checkbox's state and methods.
import { Checkbox } from '@ark-ui/react/checkbox'
import { CheckIcon } from 'lucide-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 { Checkbox } from '@ark-ui/solid/checkbox'
import { CheckIcon } from 'lucide-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/checkbox'
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>
Field
The checkbox integrates smoothly with the Field
component to handle form state, helper text, and error text for proper
accessibility.
import { Checkbox } from '@ark-ui/react/checkbox'
import { Field } from '@ark-ui/react/field'
import { CheckIcon, MinusIcon } from 'lucide-react'
export const WithField = (props: Field.RootProps) => (
<Field.Root {...props}>
<Checkbox.Root>
<Checkbox.Label>Label</Checkbox.Label>
<Checkbox.Control>
<Checkbox.Indicator>
<CheckIcon />
</Checkbox.Indicator>
<Checkbox.Indicator indeterminate>
<MinusIcon />
</Checkbox.Indicator>
</Checkbox.Control>
<Checkbox.HiddenInput />
</Checkbox.Root>
<Field.HelperText>Additional Info</Field.HelperText>
<Field.ErrorText>Error Info</Field.ErrorText>
</Field.Root>
)
import { Checkbox } from '@ark-ui/solid/checkbox'
import { Field } from '@ark-ui/solid/field'
import { CheckIcon, MinusIcon } from 'lucide-solid'
export const WithField = (props: Field.RootProps) => (
<Field.Root {...props}>
<Checkbox.Root>
<Checkbox.Label>Label</Checkbox.Label>
<Checkbox.Control>
<Checkbox.Indicator>
<CheckIcon />
</Checkbox.Indicator>
<Checkbox.Indicator indeterminate>
<MinusIcon />
</Checkbox.Indicator>
</Checkbox.Control>
<Checkbox.HiddenInput />
</Checkbox.Root>
<Field.HelperText>Additional Info</Field.HelperText>
<Field.ErrorText>Error Info</Field.ErrorText>
</Field.Root>
)
<script setup lang="ts">
import { Checkbox } from '@ark-ui/vue/checkbox'
import { Field, type FieldRootProps } from '@ark-ui/vue/field'
import { CheckIcon, MinusIcon } from 'lucide-vue-next'
const props = defineProps<FieldRootProps>()
</script>
<template>
<Field.Root v-bind="props">
<Checkbox.Root>
<Checkbox.Label>Label</Checkbox.Label>
<Checkbox.Control>
<Checkbox.Indicator>
<CheckIcon />
</Checkbox.Indicator>
<Checkbox.Indicator indeterminate>
<MinusIcon />
</Checkbox.Indicator>
</Checkbox.Control>
<Checkbox.HiddenInput />
</Checkbox.Root>
<Field.HelperText>Additional Info</Field.HelperText>
<Field.ErrorText>Error Info</Field.ErrorText>
</Field.Root>
</template>
Root Provider
Use the useCheckbox
hook to create the checkbox store and pass it to the Checkbox.RootProvider
component. This
allows you to have maximum control over the checkbox programmatically.
import { Checkbox, useCheckbox } from '@ark-ui/react/checkbox'
import { CheckIcon } from 'lucide-react'
export const RootProvider = () => {
const checkbox = useCheckbox()
return (
<>
<span>{checkbox.checked ? 'Checked' : 'UnChecked'}</span>
<Checkbox.RootProvider value={checkbox}>
<Checkbox.Label>Checkbox</Checkbox.Label>
<Checkbox.Control>
<Checkbox.Indicator>
<CheckIcon />
</Checkbox.Indicator>
</Checkbox.Control>
<Checkbox.HiddenInput />
</Checkbox.RootProvider>
</>
)
}
import { Checkbox, useCheckbox } from '@ark-ui/solid/checkbox'
import { CheckIcon } from 'lucide-solid'
export const RootProvider = () => {
const checkbox = useCheckbox()
return (
<>
<span>{checkbox().checked ? 'Checked' : 'UnChecked'}</span>
<Checkbox.RootProvider value={checkbox}>
<Checkbox.Label>Checkbox</Checkbox.Label>
<Checkbox.Control>
<Checkbox.Indicator>
<CheckIcon />
</Checkbox.Indicator>
</Checkbox.Control>
<Checkbox.HiddenInput />
</Checkbox.RootProvider>
</>
)
}
<script setup lang="ts">
import { Checkbox, useCheckbox } from '@ark-ui/vue/checkbox'
import { CheckIcon } from 'lucide-vue-next'
const checkbox = useCheckbox()
</script>
<template>
<span>{{ checkbox.checked ? 'Checked' : 'UnChecked' }}</span>
<Checkbox.RootProvider :value="checkbox">
<Checkbox.Label>Checkbox</Checkbox.Label>
<Checkbox.Control>
<Checkbox.Indicator>
<CheckIcon />
</Checkbox.Indicator>
</Checkbox.Control>
<Checkbox.HiddenInput />
</Checkbox.RootProvider>
</template>
If you're using the
Checkbox.RootProvider
component, you don't need to use theCheckbox.Root
component.
API Reference
Root
Prop | Default | Type |
---|---|---|
asChild | boolean Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. | |
checked | CheckedState The controlled checked state of the checkbox | |
defaultChecked | CheckedState The initial checked state of the checkbox when rendered. Use when you don't need to control the checked state of the checkbox. | |
disabled | boolean Whether the checkbox is disabled | |
form | string The id of the form that the checkbox belongs to. | |
id | string The 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 | boolean Whether the checkbox is invalid | |
name | string The name of the input field in a checkbox. Useful for form submission. | |
onCheckedChange | (details: CheckedChangeDetails) => void The callback invoked when the checked state changes. | |
readOnly | boolean Whether the checkbox is read-only | |
required | boolean Whether the checkbox is required | |
value | 'on' | string The value of checkbox input. Useful for form submission. |
Data Attribute | Value |
---|---|
[data-active] | Present when active or pressed |
[data-focus] | Present when focused |
[data-focus-visible] | Present when focused with keyboard |
[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 | boolean Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Data Attribute | Value |
---|---|
[data-active] | Present when active or pressed |
[data-focus] | Present when focused |
[data-focus-visible] | Present when focused with keyboard |
[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 | boolean Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. | |
defaultValue | string[] The initial value of `value` when uncontrolled | |
disabled | boolean If `true`, the checkbox group is disabled | |
invalid | boolean If `true`, the checkbox group is invalid | |
name | string The name of the input fields in the checkbox group (Useful for form submission). | |
onValueChange | (value: string[]) => void The callback to call when the value changes | |
readOnly | boolean If `true`, the checkbox group is read-only | |
value | string[] The controlled value of the checkbox group |
HiddenInput
Prop | Default | Type |
---|---|---|
asChild | boolean Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Indicator
Prop | Default | Type |
---|---|---|
asChild | boolean Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. | |
indeterminate | boolean |
Data Attribute | Value |
---|---|
[data-active] | Present when active or pressed |
[data-focus] | Present when focused |
[data-focus-visible] | Present when focused with keyboard |
[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 | boolean Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Data Attribute | Value |
---|---|
[data-active] | Present when active or pressed |
[data-focus] | Present when focused |
[data-focus-visible] | Present when focused with keyboard |
[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 | boolean Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Accessibility
Complies with the Checkbox WAI-ARIA design pattern.
Keyboard Support
Key | Description |
---|---|
Space | Toggle the checkbox |