Skip to main content

Overview

The createSelection composable extends createRegistry with selection tracking via a reactive Set of selected IDs. It supports disabled items, mandatory selection enforcement, and automatic enrollment of newly registered items. Serves as the base for createSingle, createGroup, and createStep composables.

Signature

function createSelection<
  Z extends SelectionTicketInput = SelectionTicketInput,
  E extends SelectionTicket<Z> = SelectionTicket<Z>
>(options?: SelectionOptions): SelectionContext<Z, E>
options
SelectionOptions
Configuration options
SelectionContext
object
Selection instance with tracking methods

Usage

Basic Selection

import { createSelection } from '@vuetify/v0'

const selection = createSelection({ multiple: true })

selection.onboard([
  { id: 'item-1', value: 'Item 1' },
  { id: 'item-2', value: 'Item 2' },
  { id: 'item-3', value: 'Item 3' },
])

selection.select('item-1')
selection.select('item-3')

console.log(selection.selectedIds) // Set { 'item-1', 'item-3' }
console.log(Array.from(selection.selectedValues.value)) // ['Item 1', 'Item 3']

Mandatory Selection

// Prevents deselecting last item
const selection = createSelection({ mandatory: true })

selection.onboard([
  { id: 'tab-1', value: 'Home' },
  { id: 'tab-2', value: 'Settings' },
])

selection.select('tab-1')
selection.unselect('tab-1') // Blocked - can't deselect last item

console.log(selection.selected('tab-1')) // true

Force Mandatory

// Auto-select first non-disabled item
const selection = createSelection({ mandatory: 'force' })

selection.onboard([
  { id: 'tab-1', value: 'Home' },
  { id: 'tab-2', value: 'Settings' },
])

// First item auto-selected
console.log(selection.selected('tab-1')) // true

Auto-Enrollment

// Auto-select newly registered items
const selection = createSelection({ 
  enroll: true, 
  multiple: true 
})

selection.onboard([
  { id: 'item-1', value: 'Item 1' },
  { id: 'item-2', value: 'Item 2', disabled: true },
  { id: 'item-3', value: 'Item 3' },
])

// item-1 and item-3 auto-selected (item-2 skipped - disabled)
console.log(selection.selectedIds.size) // 2
console.log(selection.selected('item-2')) // false

Disabled Items

const selection = createSelection()

selection.register({ 
  id: 'item-1', 
  value: 'Enabled',
  disabled: false 
})

selection.register({ 
  id: 'item-2', 
  value: 'Disabled',
  disabled: true 
})

selection.select('item-1') // Works
selection.select('item-2') // Blocked - item is disabled

console.log(selection.selectedIds.size) // 1

Ticket Methods

const selection = createSelection()

const ticket = selection.register({ 
  id: 'item-1', 
  value: 'Item 1' 
})

// Each ticket has selection methods
ticket.select()
console.log(ticket.isSelected.value) // true

ticket.unselect()
console.log(ticket.isSelected.value) // false

ticket.toggle()
console.log(ticket.isSelected.value) // true

Context-Level Disabled

import { ref } from 'vue'

const disabled = ref(false)
const selection = createSelection({ disabled })

selection.register({ id: 'item-1' })

selection.select('item-1') // Works
console.log(selection.selected('item-1')) // true

// Disable entire selection
disabled.value = true
selection.unselect('item-1') // Blocked
console.log(selection.selected('item-1')) // true (still selected)

Seeking Non-Disabled Items

const selection = createSelection()

selection.onboard([
  { id: 'item-1', value: 'Item 1', disabled: true },
  { id: 'item-2', value: 'Item 2' },
  { id: 'item-3', value: 'Item 3', disabled: true },
  { id: 'item-4', value: 'Item 4' },
])

const first = selection.seek('first') // Returns item-2 (skips disabled)
const last = selection.seek('last')   // Returns item-4

Computed Properties

selectedItems

Reactive Set of selected ticket objects:
const items = Array.from(selection.selectedItems.value)
items.forEach(item => {
  console.log(item.id, item.value)
})

selectedValues

Reactive Set of selected ticket values:
const values = Array.from(selection.selectedValues.value)
console.log(values) // ['Value 1', 'Value 3']

Type Safety

interface TabTicket extends SelectionTicketInput {
  label: string
  icon?: string
}

const tabs = createSelection<TabTicket>()

const ticket = tabs.register({ 
  label: 'Home', 
  icon: 'mdi-home' 
})

// Type-safe access
console.log(ticket.label) // string
console.log(ticket.icon) // string | undefined
console.log(ticket.isSelected.value) // boolean

Context Pattern

import { createSelectionContext } from '@vuetify/v0'

export const [useCheckboxes, provideCheckboxes, checkboxes] = 
  createSelectionContext()

// In parent component
provideCheckboxes()

// In child component
const checkboxes = useCheckboxes()
checkboxes.select('checkbox-1')

Inheritance Chain

createRegistry

createSelection

┌───────┬───────────┐
│       │            │
createSingle  createGroup  (others)

See Also

Build docs developers (and LLMs) love