Skip to content

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

ClassDescription
.checkboxBase checkbox wrapper
.checkbox__controlCheckbox control box
.checkbox__indicatorCheckbox checkmark or custom indicator
.checkbox__contentOptional label/description wrapper
.checkbox--primaryPrimary variant
.checkbox--secondarySecondary variant

Interactive States

StateSelector
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

PropTypeDefaultDescription
v-modelbooleanundefinedControlled selected state
checkedboolean | 'indeterminate'undefinedControlled checked state
defaultCheckedboolean | 'indeterminate'falseInitial checked state
isSelectedbooleanundefinedReact-style selected alias
defaultSelectedbooleanundefinedReact-style default selected alias
isIndeterminatebooleanundefinedForce indeterminate state
variant'primary' | 'secondary''primary'Visual variant
disabledbooleanundefinedDisable the checkbox
isDisabledbooleanundefinedReact-style disabled alias
readonlybooleanundefinedPrevent value changes
isReadOnlybooleanundefinedReact-style read-only alias
isInvalidbooleanundefinedInvalid state
requiredbooleanundefinedNative required state
isRequiredbooleanundefinedReact-style required alias
namestringundefinedForm field name
valuestringundefinedForm field value
controlClassstringundefinedClass merged onto .checkbox__control
indicatorClassstringundefinedClass merged onto .checkbox__indicator
contentClassstringundefinedClass merged onto .checkbox__content

Events

EventPayloadDescription
update:checkedboolean | 'indeterminate'Emitted when checked state changes
update:modelValuebooleanEmitted when selected state changes
changebooleanEmitted when selected state changes

Slots

SlotPropsDescription
default{ checked, isSelected, isIndeterminate, isDisabled, isInvalid, isReadOnly }Label and description content
indicator{ checked, isSelected, isIndeterminate, isDisabled, isInvalid, isReadOnly }Optional custom indicator

Released under the Apache-2.0 License.