Checkbox
Checkboxes allow users to select individual boolean options.
Import
ts
import { Button, Checkbox, Description, Label } from '@heroui-vue/vue'Usage
Basic
<template>
<Checkbox id="basic-terms">
<Label for="basic-terms">Accept terms and conditions</Label>
</Checkbox>
</template>
<script setup>
import { Checkbox, Label } from '@heroui-vue/vue'
</script>Anatomy
vue
<template>
<Checkbox>
<template #indicator="{ isSelected }">
<span v-if="isSelected">...</span>
</template>
<Label />
<Description />
</Checkbox>
</template>Disabled
<template>
<Checkbox id="feature" is-disabled>
<Label for="feature">Premium Feature</Label>
<Description>This feature is coming soon</Description>
</Checkbox>
</template>
<script setup>
import { Checkbox, Description, Label } from '@heroui-vue/vue'
</script>Default Selected
<template>
<Checkbox id="default-notifications" default-selected>
<Label for="default-notifications">Enable email notifications</Label>
</Checkbox>
</template>
<script setup>
import { Checkbox, Label } from '@heroui-vue/vue'
</script>Controlled
Status: Enabled
<template>
<div class="flex flex-col gap-3">
<Checkbox id="email-notifications" v-model="isSelected">
<Label for="email-notifications">Email notifications</Label>
</Checkbox>
<p class="text-sm text-muted">
Status: <span class="font-medium">{{ isSelected ? 'Enabled' : 'Disabled' }}</span>
</p>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { Checkbox, Label } from '@heroui-vue/vue'
const isSelected = ref(true)
</script>Indeterminate
<template>
<Checkbox
id="select-all"
:checked="checked"
:is-indeterminate="isIndeterminate"
@change="handleChange"
>
<Label for="select-all">Select all</Label>
<Description>Shows indeterminate state with a dash icon</Description>
</Checkbox>
</template>
<script setup>
import { ref } from 'vue'
import { Checkbox, Description, Label } from '@heroui-vue/vue'
const checked = ref(false)
const isIndeterminate = ref(true)
const handleChange = (next) => {
checked.value = next
isIndeterminate.value = false
}
</script>With Label
<template>
<Checkbox id="label-marketing">
<Label for="label-marketing">Send me marketing emails</Label>
</Checkbox>
</template>
<script setup>
import { Checkbox, Label } from '@heroui-vue/vue'
</script>With Description
<template>
<Checkbox id="description-notifications">
<Label for="description-notifications">Email notifications</Label>
<Description>Get notified when someone mentions you in a comment</Description>
</Checkbox>
</template>
<script setup>
import { Checkbox, Description, Label } from '@heroui-vue/vue'
</script>Render Props
<template>
<Checkbox id="render-props-terms">
<template #default="{ isSelected }">
<Label for="render-props-terms">{{ isSelected ? 'Terms accepted' : 'Accept terms' }}</Label>
<Description>
{{ isSelected ? 'Thank you for accepting' : 'Please read and accept the terms' }}
</Description>
</template>
</Checkbox>
</template>
<script setup>
import { Checkbox, Description, Label } from '@heroui-vue/vue'
</script>Form Integration
<template>
<form class="flex flex-col gap-4" @submit.prevent="handleSubmit">
<div class="flex flex-col gap-3">
<Checkbox id="form-notifications" name="notifications" value="on">
<Label for="form-notifications">Enable notifications</Label>
</Checkbox>
<Checkbox id="form-newsletter" default-selected name="newsletter" value="on">
<Label for="form-newsletter">Subscribe to newsletter</Label>
</Checkbox>
<Checkbox id="form-marketing" name="marketing" value="on">
<Label for="form-marketing">Receive marketing updates</Label>
</Checkbox>
</div>
<Button class="w-fit" size="sm" type="submit">Submit</Button>
<p v-if="message" class="text-sm text-muted">{{ message }}</p>
</form>
</template>
<script setup>
import { ref } from 'vue'
import { Button, Checkbox, Label } from '@heroui-vue/vue'
const message = ref('')
const handleSubmit = (event) => {
const formData = new FormData(event.currentTarget)
const values = Array.from(formData.entries()).map(([key, value]) => `${key}: ${value}`)
message.value = values.length ? values.join(', ') : 'No options selected'
}
</script>Invalid
<template>
<Checkbox id="agreement" is-invalid name="agreement">
<Label for="agreement">I agree to the terms</Label>
<Description>You must accept the terms to continue</Description>
</Checkbox>
</template>
<script setup>
import { Checkbox, Description, Label } from '@heroui-vue/vue'
</script>Custom Indicator
<template>
<div class="flex flex-wrap gap-4">
<Checkbox default-selected name="heart">
<template #indicator="{ isSelected }">
<svg v-if="isSelected" class="size-3 text-inherit" viewBox="0 0 24 24" fill="currentColor">
<path d="M12.62 20.81c-.34.12-.9.12-1.24 0C8.48 19.82 2 15.69 2 8.69 2 5.6 4.49 3.1 7.56 3.1c1.82 0 3.43.88 4.44 2.24a5.53 5.53 0 0 1 4.44-2.24C19.51 3.1 22 5.6 22 8.69c0 7-6.48 11.13-9.38 12.12Z" />
</svg>
</template>
<Label>Heart</Label>
</Checkbox>
<Checkbox default-selected name="plus">
<template #indicator="{ isSelected }">
<svg v-if="isSelected" class="size-3 text-inherit" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3">
<path d="M6 12h12" />
<path d="M12 18V6" />
</svg>
</template>
<Label>Plus</Label>
</Checkbox>
<Checkbox :checked="'indeterminate'" name="indeterminate">
<template #indicator="{ isIndeterminate }">
<svg v-if="isIndeterminate" class="size-3 text-inherit" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3">
<line x1="21" x2="3" y1="12" y2="12" />
</svg>
</template>
<Label>Indeterminate</Label>
</Checkbox>
</div>
</template>
<script setup>
import { Checkbox, Label } from '@heroui-vue/vue'
</script>Full Rounded
<template>
<div class="flex flex-col gap-6">
<div class="flex flex-col gap-3">
<Label class="text-muted">Rounded checkboxes</Label>
<Checkbox control-class="size-3 rounded-full" name="small-rounded">
<Label>Small size</Label>
</Checkbox>
<Checkbox control-class="size-4 rounded-full" name="default-rounded">
<Label>Default size</Label>
</Checkbox>
<Checkbox control-class="size-5 rounded-full" name="large-rounded">
<Label>Large size</Label>
</Checkbox>
<Checkbox control-class="size-6 rounded-full" name="xl-rounded">
<Label>Extra large size</Label>
</Checkbox>
</div>
</div>
</template>
<script setup>
import { Checkbox, Label } from '@heroui-vue/vue'
</script>Variants
Checkbox supports two visual variants:
primary: default field shadow.secondary: lower-emphasis styling for surfaces.
Primary variant
Secondary variant
<template>
<div class="flex flex-col gap-4">
<div class="flex flex-col gap-2">
<p class="text-sm font-medium text-muted">Primary variant</p>
<Checkbox id="primary" name="primary" variant="primary">
<Label for="primary">Primary checkbox</Label>
<Description>Standard styling with default background</Description>
</Checkbox>
</div>
<div class="flex flex-col gap-2">
<p class="text-sm font-medium text-muted">Secondary variant</p>
<Checkbox id="secondary" name="secondary" variant="secondary">
<Label for="secondary">Secondary checkbox</Label>
<Description>Lower emphasis variant for use in surfaces</Description>
</Checkbox>
</div>
</div>
</template>
<script setup>
import { Checkbox, Description, Label } from '@heroui-vue/vue'
</script>Custom Styles
<template>
<Checkbox
id="custom"
control-class="demo-checkbox-custom-control"
indicator-class="demo-checkbox-custom-indicator"
>
<Label for="custom">Custom styled checkbox</Label>
</Checkbox>
</template>
<script setup>
import { Checkbox, Label } from '@heroui-vue/vue'
</script>
<style lang="less">
.demo-checkbox-custom-control {
border: 2px solid rgb(168 85 247);
}
.checkbox[data-selected="true"] .demo-checkbox-custom-control {
background: rgb(168 85 247);
}
.demo-checkbox-custom-control::before {
background: rgb(168 85 247);
}
.demo-checkbox-custom-indicator {
color: white;
}
</style>Styling
Passing Classes
vue
<template>
<Checkbox
control-class="border-2 border-purple-500"
indicator-class="text-white"
>
<Label>Custom Checkbox</Label>
</Checkbox>
</template>CSS Classes
| Class | Description |
|---|---|
.checkbox | Base checkbox wrapper |
.checkbox__control | Checkbox control box |
.checkbox__indicator | Checkbox checkmark or custom indicator |
.checkbox__content | Optional label/description wrapper |
.checkbox--primary | Primary variant |
.checkbox--secondary | Secondary variant |
Interactive States
| State | Selector |
|---|---|
| Selected | [data-selected="true"] / [aria-checked="true"] |
| Indeterminate | [data-indeterminate="true"] |
| Invalid | [data-invalid="true"] / [aria-invalid="true"] |
| Hover | :hover / [data-hovered="true"] |
| Focus visible | :focus-visible / [data-focus-visible="true"] |
| Disabled | [aria-disabled="true"] / [data-disabled="true"] |
| Read only | [aria-readonly="true"] / [data-readonly="true"] |
| Pressed | :active / [data-pressed="true"] |
API
Props
| Prop | Type | Default | Description |
|---|---|---|---|
v-model | boolean | undefined | Controlled selected state |
checked | boolean | 'indeterminate' | undefined | Controlled checked state |
defaultChecked | boolean | 'indeterminate' | false | Initial checked state |
isSelected | boolean | undefined | React-style selected alias |
defaultSelected | boolean | undefined | React-style default selected alias |
isIndeterminate | boolean | undefined | Force indeterminate state |
variant | 'primary' | 'secondary' | 'primary' | Visual variant |
disabled | boolean | undefined | Disable the checkbox |
isDisabled | boolean | undefined | React-style disabled alias |
readonly | boolean | undefined | Prevent value changes |
isReadOnly | boolean | undefined | React-style read-only alias |
isInvalid | boolean | undefined | Invalid state |
required | boolean | undefined | Native required state |
isRequired | boolean | undefined | React-style required alias |
name | string | undefined | Form field name |
value | string | undefined | Form field value |
controlClass | string | undefined | Class merged onto .checkbox__control |
indicatorClass | string | undefined | Class merged onto .checkbox__indicator |
contentClass | string | undefined | Class merged onto .checkbox__content |
Events
| Event | Payload | Description |
|---|---|---|
update:checked | boolean | 'indeterminate' | Emitted when checked state changes |
update:modelValue | boolean | Emitted when selected state changes |
change | boolean | Emitted when selected state changes |
Slots
| Slot | Props | Description |
|---|---|---|
default | { checked, isSelected, isIndeterminate, isDisabled, isInvalid, isReadOnly } | Label and description content |
indicator | { checked, isSelected, isIndeterminate, isDisabled, isInvalid, isReadOnly } | Optional custom indicator |