Skip to main content
You are viewing Pre-Alpha documentation.
Vuetify0 Logo
Theme
Mode
Accessibility
Vuetify

Sign in

Sign in with your preferred provider to access your account.

createGroup

The createGroup composable is designed to manage a group of related components, allowing for shared state and behavior across them. It supports tri-state (mixed/indeterminate) for checkbox trees and similar use cases where items can be selected, unselected, or in a mixed state.


Intermediate100% coverageFeb 4, 2026

Usage

The createGroup composable manages a group of selectable items, letting you work with both their IDs and their position indexes. It supports selecting, unselecting, toggling, and reading the indexes of selected items.

ts
import { createGroup } from '@vuetify/v0'

// Instantiate group
const group = createGroup()

// Register items
group.register({ id: 'apple', value: 'Apple' })
group.register({ id: 'banana', value: 'Banana' })
group.register({ id: 'cherry', value: 'Cherry' })
group.register({ id: 'date', value: 'Date' })

// Select some items
group.select(['apple', 'banana'])
console.log(group.selectedIndexes.value) // Set { 0, 1 }

// Toggle an item (banana will become unselected)
group.toggle('banana')
console.log(group.selectedIndexes.value) // Set { 0 }

// Unselect apple
group.unselect('apple')
console.log(group.selectedIndexes.value) // Set {}

Examples

0 / 6 selected

Showing all:

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

  const tags = [
    { id: 'vue', label: 'Vue', color: 'bg-emerald-500' },
    { id: 'react', label: 'React', color: 'bg-sky-500' },
    { id: 'svelte', label: 'Svelte', color: 'bg-orange-500' },
    { id: 'angular', label: 'Angular', color: 'bg-red-500' },
    { id: 'solid', label: 'Solid', color: 'bg-blue-500' },
    { id: 'qwik', label: 'Qwik', color: 'bg-violet-500' },
  ]

  const group = createGroup()
  const tickets = group.onboard(tags.map(t => ({ id: t.id, value: t })))

  const checkboxIcon = computed(() => {
    if (group.isAllSelected.value) return 'i-lucide-check-square'
    if (group.isMixed.value) return 'i-lucide-minus-square'
    return 'i-lucide-square'
  })

  const results = computed(() => {
    if (group.isNoneSelected.value) return tags
    return tags.filter(t => group.selected(t.id))
  })
</script>

<template>
  <div class="space-y-6">
    <!-- Header with tri-state checkbox -->
    <div class="flex items-center justify-between">
      <button
        class="flex items-center gap-2 text-sm font-medium text-on-surface-variant hover:text-on-surface transition-colors"
        @click="group.toggleAll()"
      >
        <div
          class="size-5 transition-transform"
          :class="checkboxIcon"
          :style="{ transform: group.isMixed.value ? 'rotate(-90deg)' : 'rotate(0deg)' }"
        />
        <span>{{ group.isAllSelected.value ? 'Clear all' : 'Select all' }}</span>
      </button>
      <span class="text-xs text-on-surface-variant">
        {{ group.selectedIds.size }} / {{ group.size }} selected
      </span>
    </div>

    <!-- Chip cloud -->
    <div class="flex flex-wrap gap-2">
      <button
        v-for="ticket in tickets"
        :key="ticket.id"
        class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-full text-sm font-medium border transition-all duration-200"
        :class="[
          ticket.isSelected.value
            ? 'bg-surface text-on-surface border-primary scale-105'
            : 'bg-surface text-on-surface-variant border-divider hover:border-primary/50'
        ]"
        @click="ticket.toggle()"
      >
        <span
          class="size-2 rounded-full transition-opacity duration-200"
          :class="[ticket.value.color, ticket.isSelected.value ? 'opacity-100' : 'opacity-50']"
        />
        {{ ticket.value.label }}
        <span
          class="i-lucide-check size-3.5 transition-all duration-200"
          :class="ticket.isSelected.value ? 'opacity-100 scale-100' : 'opacity-0 scale-0'"
        />
      </button>
    </div>

    <!-- Results preview -->
    <div class="pt-4 border-t border-divider">
      <p class="text-xs text-on-surface-variant mb-2">
        {{ group.isNoneSelected.value ? 'Showing all' : 'Filtered results' }}:
      </p>
      <div class="flex flex-wrap gap-1">
        <span
          v-for="tag in results"
          :key="tag.id"
          class="px-2 py-0.5 text-xs rounded bg-surface-variant text-on-surface-variant"
        >
          {{ tag.label }}
        </span>
      </div>
    </div>
  </div>
</template>

Architecture

createGroup extends createSelection with multi-select and tri-state capabilities:

Group Selection Hierarchy

Use controls to zoom and pan. Click outside or press Escape to close.

Group Selection Hierarchy

Reactivity

Group selection state is always reactive, including the tri-state mixedIds set.

Property/MethodReactiveNotes
selectedIdsshallowReactive(Set) — always reactive
mixedIdsshallowReactive(Set) — tracks indeterminate state
selectedIndexesComputed from selectedIds
isAllSelectedComputed from selectedIds and collection size
selectedItemsComputed from selectedIds
selectedValuesComputed from selectedItems
ticket isSelectedComputed from selectedIds
Tip

Tri-state support mixedIds is reactive and updates automatically for indeterminate checkbox states in tree structures.

API Reference

The following API details are for the createGroup composable.

Functions

createGroup

(_options?: GroupOptions) => R

Creates a new group instance with batch selection and tri-state support. Extends `createSelection` to support selecting, unselecting, and toggling multiple items at once by passing an array of IDs. Adds tri-state (mixed/indeterminate) support for checkbox trees and similar use cases.

createGroupContext

(_options?: GroupContextOptions) => ContextTrinity<R>

Creates a new group context.

useGroup

(namespace?: string) => R

Returns the current group instance.

Options

events

boolean

Enable event emission for registry operations

Default: false

reactive

boolean

Enable reactive behavior for registry operations

Default: false

disabled

MaybeRefOrGetter<boolean>

When true, the entire selection instance is disabled.

enroll

MaybeRefOrGetter<boolean>

When true, newly registered items are automatically selected if not disabled. Useful for pre-selecting items in multi-select scenarios.

mandatory

MaybeRefOrGetter<boolean | "force">

Controls mandatory selection behavior: - `false` (default): No mandatory selection enforcement - `true`: Prevents deselecting the last selected item (user must always have one selected) - `'force'`: Automatically selects the first non-disabled item on registration

multiple

MaybeRefOrGetter<boolean>

When true, treats the selection as an array

Properties

collection

ReadonlyMap<ID, Z>

The collection of tickets in the registry

size

number

The number of tickets in the registry

selectedIds

Reactive<Set<ID>>

Set of selected ticket IDs

selectedItems

ComputedRef<Set<E>>

Set of selected ticket instances

selectedValues

ComputedRef<Set<unknown>>

Set of selected ticket values

disabled

MaybeRef<boolean>

Disable state for the entire selection instance

selectedIndexes

ComputedRef<Set<number>>

mixedIds

Reactive<Set<ID>>

Set of mixed/indeterminate ticket IDs

mixedItems

ComputedRef<Set<E>>

Set of mixed/indeterminate ticket instances

isNoneSelected

ComputedRef<boolean>

Whether no items are currently selected

isAllSelected

ComputedRef<boolean>

Whether all selectable (non-disabled) items are selected

isMixed

ComputedRef<boolean>

Whether some but not all selectable items are selected

Methods

clear

() => void

Clear the entire registry

has

(id: ID) => boolean

Check if a ticket exists by ID

keys

() => readonly ID[]

Get all registered IDs

browse

(value: Z["value"]) => ID[] | undefined

Browse for an ID(s) by value

lookup

(index: number) => ID | undefined

lookup a ticket by index number

get

(id: ID) => Z | undefined

Get a ticket by ID

upsert

(id: ID, ticket?: Partial<Z>) => Z

Update or insert a ticket by ID

values

() => readonly Z[]

Get all values of registered tickets

entries

() => readonly [ID, Z][]

Get all entries of registered tickets

unregister

(id: ID) => void

Unregister a ticket by ID

reindex

() => void

Reset the index directory and update all tickets

seek

(direction?: "first" | "last", from?: number, predicate?: (ticket) => boolean) => Z | undefined

Seek for a ticket based on direction and optional predicate

on

<K extends Extensible<RegistryEventName>>(event: K, cb: EventHandler<Z, K>) => void

Listen for registry events

off

<K extends Extensible<RegistryEventName>>(event: K, cb: EventHandler<Z, K>) => void

Stop listening for registry events

emit

<K extends Extensible<RegistryEventName>>(event: K, data: EventPayload<Z, K>) => void

Emit an event with data

dispose

() => void

Clears the registry and removes all listeners

offboard

(ids: ID[]) => void

Offboard multiple tickets at once

batch

<R>(fn: () => R) => R

Execute operations in a batch, deferring cache invalidation and event emission until complete

reset

() => void

Clear all selected IDs and reindexes

selected

(id: ID) => boolean

Check if a ticket is selected by ID

mandate

() => void

Mandates selected ID based on "mandatory" Option

select

(ids: ID | ID[]) => void

Select one or more Tickets by ID

unselect

(ids: ID | ID[]) => void

Unselect one or more Tickets by ID

toggle

(ids: ID | ID[]) => void

Toggle one or more Tickets ON and OFF by ID

mix

(ids: ID | ID[]) => void

Set one or more Tickets to mixed/indeterminate state by ID

unmix

(ids: ID | ID[]) => void

Clear mixed/indeterminate state from one or more Tickets by ID

mixed

(id: ID) => boolean

Check if a ticket is in mixed/indeterminate state by ID

selectAll

() => void

Select all selectable (non-disabled) items

unselectAll

() => void

Unselect all items (respects mandatory option)

toggleAll

() => void

Toggle between all selected and none selected

register

(ticket?: Partial<Z>) => E

Register a new ticket (accepts input type, returns output type)

onboard

(registrations: Partial<Z>[]) => E[]

Onboard multiple tickets at once

Was this page helpful?

© 2016-1970 Vuetify, LLC
Ctrl+/