Skip to main content

Checkbox

A headless checkbox component that provides accessible, flexible checkbox functionality. Supports standalone boolean state or multi-selection within groups, with full keyboard navigation and form integration.

Features

  • Dual-mode operation: Standalone with v-model or group multi-selection
  • Tri-state support: Checked, unchecked, and indeterminate states
  • Full accessibility: ARIA attributes, keyboard navigation, screen reader support
  • Form integration: Automatic hidden input generation for native form submission
  • Select all: Built-in component for bulk selection in groups
  • Flexible rendering: Works with any element via as prop or renderless mode

Basic Usage

Standalone Checkbox

<script setup lang="ts">
import { Checkbox } from '@vuetify/v0'
import { ref } from 'vue'

const agreed = ref(false)
</script>

<template>
  <label>
    <Checkbox.Root v-model="agreed">
      <Checkbox.Indicator></Checkbox.Indicator>
    </Checkbox.Root>
    I agree to the terms
  </label>
</template>

Checkbox Group

<script setup lang="ts">
import { Checkbox } from '@vuetify/v0'
import { ref } from 'vue'

const selected = ref<string[]>([])
</script>

<template>
  <Checkbox.Group v-model="selected">
    <label>
      <Checkbox.Root value="typescript">
        <Checkbox.Indicator></Checkbox.Indicator>
      </Checkbox.Root>
      TypeScript
    </label>
    <label>
      <Checkbox.Root value="vue">
        <Checkbox.Indicator></Checkbox.Indicator>
      </Checkbox.Root>
      Vue
    </label>
    <label>
      <Checkbox.Root value="vite">
        <Checkbox.Indicator></Checkbox.Indicator>
      </Checkbox.Root>
      Vite
    </label>
  </Checkbox.Group>
</template>

Components

Checkbox.Root

The main checkbox component. Supports standalone mode with v-model or group mode within Checkbox.Group.
modelValue
boolean
default:"false"
The checked state (standalone mode only)
value
unknown
Value associated with this checkbox (used in group mode and form submission)
name
string
Form field name. When provided, automatically renders a hidden input for form submission
disabled
boolean | Ref<boolean>
default:"false"
Disables the checkbox, preventing interaction
indeterminate
boolean | Ref<boolean>
default:"false"
Sets the indeterminate/mixed state (standalone mode)
label
string
Optional display label (passed to slot props)
id
string
Unique identifier (auto-generated if not provided)
form
string
Associate with a form element by ID
as
string
default:"'button'"
HTML element to render as
renderless
boolean
default:"false"
Render only slot content without wrapper element
namespace
string
default:"'v0:checkbox:root'"
Context namespace for child components
groupNamespace
string
default:"'v0:checkbox:group'"
Namespace for connecting to parent group

Slot Props

isChecked
boolean
Whether the checkbox is checked
isMixed
boolean
Whether the checkbox is in indeterminate state
isDisabled
boolean
Whether the checkbox is disabled
select
() => void
Function to check the checkbox
unselect
() => void
Function to uncheck the checkbox
toggle
() => void
Function to toggle checkbox state
attrs
object
Pre-computed ARIA and data attributes to bind to the element

Checkbox.Group

Container for managing multiple checkboxes with multi-selection support.
modelValue
T[]
default:"[]"
Array of selected values
disabled
boolean
default:"false"
Disables all checkboxes in the group
enroll
boolean
default:"false"
Auto-select all non-disabled items on mount
mandatory
boolean | 'force'
default:"false"
  • false: No enforcement
  • true: Prevents deselecting the last item
  • 'force': Auto-selects first non-disabled item
label
string
Accessible name for the group
as
string
default:"'div'"
HTML element to render as
renderless
boolean
default:"false"
Render only slot content without wrapper
namespace
string
default:"'v0:checkbox:group'"
Context namespace for child checkboxes

Slot Props

isDisabled
boolean
Whether the group is disabled
isNoneSelected
boolean
Whether no items are selected
isAllSelected
boolean
Whether all selectable items are selected
isMixed
boolean
Whether some but not all items are selected
selectAll
() => void
Select all non-disabled items
unselectAll
() => void
Unselect all items
toggleAll
() => void
Toggle between all selected and none selected

Checkbox.Indicator

Visual indicator that displays when the checkbox is checked or indeterminate.
as
string
default:"'span'"
HTML element to render as
renderless
boolean
default:"false"
Render only slot content without wrapper
namespace
string
default:"'v0:checkbox:root'"
Context namespace to inject from parent

Slot Props

isChecked
boolean
Whether the checkbox is checked
isMixed
boolean
Whether the checkbox is indeterminate
attrs
object
Contains data-state and visibility style
The indicator is automatically hidden via visibility: hidden when the checkbox is unchecked and not indeterminate.

Checkbox.SelectAll

Special checkbox for selecting/deselecting all items in a group. Must be used within Checkbox.Group.
label
string
Accessible label for the select all checkbox
disabled
boolean | Ref<boolean>
default:"false"
Disables the select all checkbox
as
string
default:"'button'"
HTML element to render as
renderless
boolean
default:"false"
Render only slot content without wrapper
namespace
string
default:"'v0:checkbox:root'"
Context namespace for child indicator
groupNamespace
string
default:"'v0:checkbox:group'"
Namespace for connecting to parent group

Slot Props

isAllSelected
boolean
Whether all items are selected
isMixed
boolean
Whether some but not all items are selected
isDisabled
boolean
Whether the select all is disabled
selectAll
() => void
Select all items
toggleAll
() => void
Toggle all items
The SelectAll component does NOT register itself as a group item. It only controls the group’s aggregate state.

Checkbox.HiddenInput

Hidden input for native form submission. Automatically rendered when name prop is provided to Checkbox.Root.
name
string
Form field name (required)
value
unknown
Value to submit when checked (overrides context value)
form
string
Associate with form by ID (overrides context form)
namespace
string
default:"'v0:checkbox:root'"
Context namespace to inject from parent

Advanced Examples

Indeterminate State

<script setup lang="ts">
import { Checkbox } from '@vuetify/v0'
import { ref, computed } from 'vue'

const items = ref(['item1', 'item2', 'item3'])
const selected = ref<string[]>(['item1'])

const parentState = computed(() => {
  if (selected.value.length === 0) return false
  if (selected.value.length === items.value.length) return true
  return 'indeterminate'
})
</script>

<template>
  <label>
    <Checkbox.Root 
      :model-value="parentState === true" 
      :indeterminate="parentState === 'indeterminate'"
      @click="selected = parentState ? [] : [...items]"
    >
      <Checkbox.Indicator></Checkbox.Indicator>
    </Checkbox.Root>
    Select all
  </label>

  <Checkbox.Group v-model="selected">
    <label v-for="item in items" :key="item">
      <Checkbox.Root :value="item">
        <Checkbox.Indicator></Checkbox.Indicator>
      </Checkbox.Root>
      {{ item }}
    </label>
  </Checkbox.Group>
</template>

Renderless Mode

<script setup lang="ts">
import { Checkbox } from '@vuetify/v0'
import { ref } from 'vue'

const agreed = ref(false)
</script>

<template>
  <Checkbox.Root v-model="agreed" renderless v-slot="{ attrs, isChecked }">
    <div 
      v-bind="attrs"
      class="custom-checkbox"
      :class="{ checked: isChecked }"
    >
      <Checkbox.Indicator renderless v-slot="{ isChecked }">
        <svg v-if="isChecked" class="checkmark">
          <path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z" />
        </svg>
      </Checkbox.Indicator>
    </div>
  </Checkbox.Root>
</template>

Form Integration

<script setup lang="ts">
import { Checkbox } from '@vuetify/v0'
import { ref } from 'vue'

const preferences = ref<string[]>([])

function handleSubmit(event: Event) {
  const formData = new FormData(event.target as HTMLFormElement)
  const selected = formData.getAll('preferences')
  console.log('Selected:', selected)
}
</script>

<template>
  <form @submit.prevent="handleSubmit">
    <Checkbox.Group v-model="preferences">
      <label>
        <Checkbox.Root name="preferences" value="email">
          <Checkbox.Indicator></Checkbox.Indicator>
        </Checkbox.Root>
        Email notifications
      </label>
      <label>
        <Checkbox.Root name="preferences" value="sms">
          <Checkbox.Indicator></Checkbox.Indicator>
        </Checkbox.Root>
        SMS notifications
      </label>
    </Checkbox.Group>
    <button type="submit">Save</button>
  </form>
</template>

Accessibility

  • Uses role="checkbox" and aria-checked for proper screen reader support
  • Supports keyboard navigation (Space to toggle)
  • Manages tabindex for proper focus management
  • Provides aria-disabled when disabled
  • Group uses role="group" with optional aria-label
  • Roving tabindex not used (each checkbox is independently tabbable)

Type Safety

All components are fully typed with TypeScript generics:
import type { 
  CheckboxRootProps,
  CheckboxGroupProps,
  CheckboxIndicatorProps,
  CheckboxSelectAllProps,
  CheckboxState // 'checked' | 'unchecked' | 'indeterminate'
} from '@vuetify/v0'

Build docs developers (and LLMs) love