CheckboxGroup
CheckboxGroup groups related checkboxes and manages their selected values.
Import
vue
<script setup lang="ts">
import { Checkbox, CheckboxGroup } from '@heroui-vue/vue'
</script>Usage
Basic
Choose all that apply
<template>
<CheckboxGroup v-model="selectedInterests" name="interests">
<Label>Select your interests</Label>
<Description>Choose all that apply</Description>
<Checkbox value="coding">
<Label>Coding</Label>
<Description>Love building software</Description>
</Checkbox>
<Checkbox value="design">
<Label>Design</Label>
<Description>Enjoy creating beautiful interfaces</Description>
</Checkbox>
<Checkbox value="writing">
<Label>Writing</Label>
<Description>Passionate about content creation</Description>
</Checkbox>
</CheckboxGroup>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { Checkbox, CheckboxGroup, Description, Label } from '@heroui-vue/vue'
const selectedInterests = ref<string[]>(['coding'])
</script>In Surface
When used inside a Surface component, use variant="secondary" on the checkbox group to apply the lower emphasis checkbox controls.
Choose all that apply
<template>
<Surface class="demo-checkbox-group-surface">
<CheckboxGroup v-model="selectedInterests" name="interests" variant="secondary">
<Label>Select your interests</Label>
<Description>Choose all that apply</Description>
<Checkbox value="coding">
<Label>Coding</Label>
<Description>Love building software</Description>
</Checkbox>
<Checkbox value="design">
<Label>Design</Label>
<Description>Enjoy creating beautiful interfaces</Description>
</Checkbox>
<Checkbox value="writing">
<Label>Writing</Label>
<Description>Passionate about content creation</Description>
</Checkbox>
</CheckboxGroup>
</Surface>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { Checkbox, CheckboxGroup, Description, Label, Surface } from '@heroui-vue/vue'
const selectedInterests = ref<string[]>(['coding'])
</script>
<style lang="less">
.demo-checkbox-group-surface {
width: min(100%, 28rem);
padding: 1.5rem;
border-radius: 1.5rem;
text-align: left;
}
</style>With Custom Indicator
Select the features you want
<template>
<CheckboxGroup v-model="selectedFeatures" name="features">
<Label>Features</Label>
<Description>Select the features you want</Description>
<Checkbox value="notifications">
<template #indicator="{ isSelected }">
<svg
v-if="isSelected"
aria-hidden="true"
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-width="2"
viewBox="0 0 24 24"
>
<path d="M6 18L18 6M6 6l12 12" />
</svg>
</template>
<Label>Email notifications</Label>
<Description>Receive updates via email</Description>
</Checkbox>
<Checkbox value="newsletter">
<template #indicator="{ isSelected }">
<svg
v-if="isSelected"
aria-hidden="true"
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-width="2"
viewBox="0 0 24 24"
>
<path d="M6 18L18 6M6 6l12 12" />
</svg>
</template>
<Label>Newsletter</Label>
<Description>Get weekly newsletters</Description>
</Checkbox>
</CheckboxGroup>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { Checkbox, CheckboxGroup, Description, Label } from '@heroui-vue/vue'
const selectedFeatures = ref<string[]>(['newsletter'])
</script>Indeterminate
<template>
<div class="demo-checkbox-group-indeterminate">
<Checkbox
value="all"
:is-indeterminate="selectedValues.length > 0 && selectedValues.length < allOptions.length"
:is-selected="selectedValues.length === allOptions.length"
@change="handleSelectAll"
>
<Label>Select all</Label>
</Checkbox>
<CheckboxGroup v-model="selectedValues" class="demo-checkbox-group-nested">
<Checkbox value="coding">
<Label>Coding</Label>
</Checkbox>
<Checkbox value="design">
<Label>Design</Label>
</Checkbox>
<Checkbox value="writing">
<Label>Writing</Label>
</Checkbox>
</CheckboxGroup>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { Checkbox, CheckboxGroup, Label } from '@heroui-vue/vue'
const allOptions = ['coding', 'design', 'writing']
const selectedValues = ref<string[]>(['coding'])
const handleSelectAll = (isSelected: boolean) => {
selectedValues.value = isSelected ? [...allOptions] : []
}
</script>
<style lang="less">
.demo-checkbox-group-indeterminate {
display: flex;
flex-direction: column;
align-items: flex-start;
}
.demo-checkbox-group-nested {
margin-left: 1.5rem;
}
</style>Controlled
<template>
<CheckboxGroup v-model="selectedSkills" class="demo-checkbox-group-controlled" name="skills">
<Label>Your skills</Label>
<Checkbox value="coding">
<Label>Coding</Label>
</Checkbox>
<Checkbox value="design">
<Label>Design</Label>
</Checkbox>
<Checkbox value="writing">
<Label>Writing</Label>
</Checkbox>
<Label class="demo-checkbox-group-selected">
Selected: {{ selectedSkills.join(', ') || 'None' }}
</Label>
</CheckboxGroup>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { Checkbox, CheckboxGroup, Label } from '@heroui-vue/vue'
const selectedSkills = ref<string[]>(['coding', 'design'])
</script>
<style lang="less">
.demo-checkbox-group-controlled {
min-width: 20rem;
}
.demo-checkbox-group-selected {
margin-block: 1rem;
color: var(--color-muted);
font-size: 0.875rem;
}
</style>Validation
<template>
<form class="demo-checkbox-group-form" @submit.prevent="handleSubmit">
<CheckboxGroup
v-model="selectedPreferences"
name="preferences"
is-required
@invalid="showError = true"
>
<Label>Preferences</Label>
<Checkbox value="email">
<Label>Email notifications</Label>
</Checkbox>
<Checkbox value="sms">
<Label>SMS notifications</Label>
</Checkbox>
<Checkbox value="push">
<Label>Push notifications</Label>
</Checkbox>
<FieldError v-if="showError">
Please select at least one notification method.
</FieldError>
</CheckboxGroup>
<Button type="submit">Submit</Button>
</form>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue'
import { Button, Checkbox, CheckboxGroup, FieldError, Label } from '@heroui-vue/vue'
const selectedPreferences = ref<string[]>([])
const showError = ref(false)
const handleSubmit = () => {
showError.value = selectedPreferences.value.length === 0
if (!showError.value) {
window.alert(`Selected preferences: ${selectedPreferences.value.join(', ')}`)
}
}
watch(selectedPreferences, (value) => {
if (value.length > 0) {
showError.value = false
}
})
</script>
<style lang="less">
.demo-checkbox-group-form {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 1rem;
padding: 1rem;
}
</style>Disabled
Feature selection is temporarily disabled
<template>
<CheckboxGroup is-disabled name="disabled-features">
<Label>Features</Label>
<Description>Feature selection is temporarily disabled</Description>
<Checkbox value="feature1">
<Label>Feature 1</Label>
<Description>This feature is coming soon</Description>
</Checkbox>
<Checkbox value="feature2">
<Label>Feature 2</Label>
<Description>This feature is coming soon</Description>
</Checkbox>
</CheckboxGroup>
</template>
<script setup lang="ts">
import { Checkbox, CheckboxGroup, Description, Label } from '@heroui-vue/vue'
</script>Features and Add-ons Example
Choose how you want to receive updates
<template>
<div class="demo-checkbox-addons">
<CheckboxGroup name="notification-preferences">
<Label>Notification preferences</Label>
<Description>Choose how you want to receive updates</Description>
<div class="demo-checkbox-addons__list">
<Checkbox
v-for="addon in addOns"
:key="addon.value"
:value="addon.value"
class="demo-checkbox-addons__item"
variant="secondary"
>
<span class="demo-checkbox-addons__icon" aria-hidden="true">
<component :is="addon.icon" />
</span>
<span class="demo-checkbox-addons__content">
<Label>{{ addon.title }}</Label>
<Description>{{ addon.description }}</Description>
</span>
</Checkbox>
</div>
</CheckboxGroup>
</div>
</template>
<script setup lang="ts">
import { h } from 'vue'
import { Checkbox, CheckboxGroup, Description, Label } from '@heroui-vue/vue'
const iconAttrs = {
fill: 'none',
viewBox: '0 0 24 24',
stroke: 'currentColor',
'stroke-width': 2.2,
}
const MailIcon = () =>
h('svg', iconAttrs, [
h('path', {
d: 'M4 7.5h16v9H4z',
'stroke-linejoin': 'round',
}),
h('path', {
d: 'm5 8 7 5 7-5',
'stroke-linecap': 'round',
'stroke-linejoin': 'round',
}),
])
const ChatIcon = () =>
h('svg', iconAttrs, [
h('path', {
d: 'M5 6.5h14v8H9l-4 3v-11Z',
'stroke-linecap': 'round',
'stroke-linejoin': 'round',
}),
])
const BellIcon = () =>
h('svg', iconAttrs, [
h('path', {
d: 'M8 17h8M10 20h4M6.5 15.5h11l-1.2-2V10a4.3 4.3 0 0 0-8.6 0v3.5l-1.2 2Z',
'stroke-linecap': 'round',
'stroke-linejoin': 'round',
}),
])
const addOns = [
{
description: 'Receive updates via email',
icon: MailIcon,
title: 'Email Notifications',
value: 'email',
},
{
description: 'Get instant SMS notifications',
icon: ChatIcon,
title: 'SMS Alerts',
value: 'sms',
},
{
description: 'Browser and mobile push alerts',
icon: BellIcon,
title: 'Push Notifications',
value: 'push',
},
]
</script>
<style lang="less">
.demo-checkbox-addons {
display: flex;
width: 100%;
min-width: 20rem;
flex-direction: column;
align-items: center;
gap: 2.5rem;
padding: 2rem 1rem;
}
.demo-checkbox-addons__list {
display: flex;
width: 100%;
min-width: 20rem;
flex-direction: column;
gap: 0.5rem;
}
.demo-checkbox-addons__item {
position: relative;
flex-direction: column;
gap: 1rem;
border-radius: 1.5rem;
background: var(--color-surface);
padding: 1rem 1.25rem;
transition: background-color 150ms var(--ease-out), transform 150ms var(--ease-out);
}
.demo-checkbox-addons__item[data-selected='true'] {
background: color-mix(in oklab, var(--color-accent) 10%, transparent);
}
.demo-checkbox-addons__item [data-slot='checkbox-control'] {
position: absolute;
top: 0.75rem;
right: 1rem;
width: 1.25rem;
height: 1.25rem;
border-radius: 999px;
}
.demo-checkbox-addons__item [data-slot='checkbox-control']::before {
border-radius: 999px;
}
.demo-checkbox-addons__item [data-slot='checkbox-content'] {
flex-direction: row;
align-items: flex-start;
justify-content: flex-start;
gap: 1rem;
padding-right: 1.75rem;
}
.demo-checkbox-addons__icon {
display: inline-flex;
width: 1.35rem;
height: 1.35rem;
flex-shrink: 0;
align-items: center;
justify-content: center;
color: var(--color-accent);
}
.demo-checkbox-addons__icon svg {
width: 1.35rem;
height: 1.35rem;
}
.demo-checkbox-addons__content {
display: flex;
min-width: 0;
flex-direction: column;
gap: 0.25rem;
}
</style>Custom Render Function
Choose all that apply
Rendered with scoped slot value: coding
<template>
<CheckboxGroup
v-slot="{ value }"
v-model="selectedInterests"
class="demo-checkbox-group-render"
name="interests"
>
<Label>Select your interests</Label>
<Description>Choose all that apply</Description>
<Checkbox value="coding">
<Label>Coding</Label>
<Description>Love building software</Description>
</Checkbox>
<Checkbox value="design">
<Label>Design</Label>
<Description>Enjoy creating beautiful interfaces</Description>
</Checkbox>
<Checkbox value="writing">
<Label>Writing</Label>
<Description>Passionate about content creation</Description>
</Checkbox>
<Description>Rendered with scoped slot value: {{ value.join(', ') || 'None' }}</Description>
</CheckboxGroup>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { Checkbox, CheckboxGroup, Description, Label } from '@heroui-vue/vue'
const selectedInterests = ref<string[]>(['coding'])
</script>
<style lang="less">
.demo-checkbox-group-render {
min-width: 20rem;
}
</style>Anatomy
vue
<template>
<CheckboxGroup v-model="values" name="interests">
<Label>Select your interests</Label>
<Description>Choose all that apply</Description>
<Checkbox value="coding">
<Label>Coding</Label>
</Checkbox>
</CheckboxGroup>
</template>API
CheckboxGroup Props
| Prop | Type | Default | Description |
|---|---|---|---|
modelValue | string[] | undefined | Controlled selected values. |
value | string[] | undefined | Alternative controlled selected values. |
defaultValue | string[] | [] | Initial uncontrolled selected values. |
name | string | undefined | Name passed to child checkboxes. |
variant | 'primary' | 'secondary' | 'primary' | Variant inherited by child checkboxes. |
isDisabled | boolean | false | Disable all child checkboxes. |
isInvalid | boolean | false | Mark the group and child checkboxes invalid. |
isRequired | boolean | false | Mark the group and child checkboxes required. |
Events
| Event | Payload | Description |
|---|---|---|
update:modelValue | string[] | Emitted when selected values change. |
update:value | string[] | Emitted for value-style controlled usage. |
change | string[] | Emitted after any child checkbox toggles. |