Skip to main content
Vuetify0 is now a release candidate!
Vuetify0 Logo
Theme
Mode
Palettes
Accessibility
Vuetify One
Sign in to Vuetify One

Access premium tools across the Vuetify ecosystem — Bin, Play, Studio, and more.

Not a subscriber? See what's included

Checkbox

A checkbox for boolean state or multi-selection groups with tri-state support.

Usage

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

<template>
  <label class="inline-flex items-center gap-2">
    <Checkbox.Root class="size-5 border rounded inline-flex items-center justify-center border-divider">
      <Checkbox.Indicator class="text-primary text-sm">✓</Checkbox.Indicator>
    </Checkbox.Root>

    <span>I agree to the terms and conditions</span>
  </label>
</template>

Anatomy

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

<template>
  <Checkbox.Group>
    <Checkbox.SelectAll>
      <Checkbox.Indicator />
    </Checkbox.SelectAll>

    <Checkbox.Root>
      <Checkbox.Indicator />
    </Checkbox.Root>

    <Checkbox.HiddenInput />
  </Checkbox.Group>
</template>

Examples

Inbox Bulk-Select with Action Bar

An email-style triage list that shows the full multi-select surface working together: Checkbox.Group holds an array v-model of selected message ids, each row is a Checkbox.Root bound to :value="email.id", and a Checkbox.SelectAll header drives the whole list. Selecting a few rows puts the header into its tri-state — checked when every row is selected, empty when none are, and indeterminate when the selection is partial. The Checkbox.Indicator inside SelectAll reads the isMixed slot prop to swap a dash for the checkmark, and the same primary fill is applied to both data-[state=checked] and data-[state=indeterminate] so the header always reads as “active” against unchecked siblings.

The interesting detail is how little wiring the group needs. Checkbox.Root items auto-register with the nearest Checkbox.Group, so the v-model array is the single source of truth — the live count, the conditional action bar, and the archive / remove handlers all derive from that one array. The action bar operates on the selected ids and then clears the selection. Row backgrounds light up through the has-[[data-state=checked]] selector rather than a JS-driven class, keeping the styling declarative. For per-item form submission, add a name to each Checkbox.Root (which auto-renders its hidden input) — see the Form Integration recipe below.

Reach for this whenever a list needs a header “select all” plus per-row toggles and batch actions — mail clients, file managers, data-grid row selection. For the underlying multi-select logic, see createGroup; for the provider primitive the group is built on, see Group; for single-choice variants, see Radio.

FileRole
useInboxSelection.tsComposable — email data, selection array, count, and archive/delete/reset behavior
InboxList.vueReusable component — renders the Checkbox.Group with a tri-state SelectAll, per-row Checkbox.Root items, and the bulk action bar
inbox-selection.vueEntry — wires the composable to the list and adds the status line + reset chrome
0 of 5 selected

Recipes

Form Integration

Pass the name prop on Checkbox.Root and a hidden native checkbox is rendered automatically. No Checkbox.HiddenInput placement is required:

vue
<template>
  <Checkbox.Root name="agree" value="yes">
    <Checkbox.Indicator>✓</Checkbox.Indicator>
  </Checkbox.Root>
</template>

Checkbox.HiddenInput is exported as an internal building block for custom layouts, but auto-rendering via name is the only supported form integration path — placing Checkbox.HiddenInput as a child of a Checkbox.Root that already has a name will produce two hidden inputs.

Styling with Data Attributes

Checkbox.Root exposes data attributes for CSS styling without conditional classes:

AttributeValuesNotes
data-statechecked, unchecked, indeterminateReflects current visual state
data-disabledtruePresent only when disabled
vue
<template>
  <Checkbox.Root class="size-5 rounded border data-[state=checked]:bg-primary data-[disabled]:opacity-50">
    <Checkbox.Indicator>✓</Checkbox.Indicator>
  </Checkbox.Root>
</template>

Accessibility

The Checkbox.Root component renders as a button and handles all ARIA attributes automatically:

  • role="checkbox" for proper semantics

  • aria-checked reflects state (true, false, or "mixed")

  • aria-disabled when checkbox is disabled

  • aria-label from the label prop

  • tabindex="0" for keyboard focus (removed when disabled)

  • Space key toggles the checkbox (Enter works when rendered as button)

For custom implementations, use renderless mode and bind the attrs slot prop to your element:

vue
<template>
  <Checkbox.Root v-slot="{ attrs }" renderless>
    <div v-bind="attrs">
      <!-- Custom checkbox visual -->
    </div>
  </Checkbox.Root>
</template>

FAQ

Discord
Need help? Join our community for support and discussions ↗
Was this page helpful?

Ctrl+/