Skip to main content
Vuetify0 is now in alpha!
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

Composables

Type-safe composables for headless UI. Components wrap these composables—you can use either approach.

Minimal Reactivity

Vuetify0 composables use the absolute minimum reactivity required to fulfill their responsibilities. This deliberate constraint keeps bundle sizes small, maximizes performance, and gives you full control over what triggers updates.

Tip

See Benchmarks for performance data and what the size ratings mean.

What’s Reactive

CategoryReactiveWhy
Selection state (selectedIds, selectedValues)UI must reflect selection changes
Ticket isSelected, isMixedPer-item binding in templates
Plugin state (useTheme, useLocale, etc.)App-wide singletons shared across components
Registry collections (values(), keys())Opt in via reactive: true or useProxyRegistry
Ticket fields (custom props)Opt in via reactive: true
Registry sizeComputed on access
Queue / Timeline dataOpt in via reactive: true; queue also auto-fires events

The reactive Option

For direct Vue reactivity on the collection and tickets themselves, pass reactive: true to the registry:

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

  const registry = createRegistry({ reactive: true })

  const input = defineModel({ default: '' })

  function onAdd () {
    if (!input.value.trim()) return
    registry.register({ value: input.value.trim() })
    input.value = ''
  }
</script>

<template>
  <div class="flex gap-2 mb-3">
    <input
      v-model="input"
      class="border border-divider rounded px-2 py-1 text-sm bg-surface text-on-surface flex-1"
      placeholder="Add item..."
      @keydown.enter="onAdd"
    />
    <button class="px-3 py-1 text-sm rounded bg-primary text-on-primary" @click="onAdd">Add</button>
  </div>

  <ul class="space-y-1">
    <li
      v-for="ticket in registry.values()"
      :key="ticket.id"
      class="flex items-center justify-between text-sm px-2 py-1 rounded border border-divider"
    >
      {{ ticket.value }}
      <button class="text-xs opacity-50 hover:opacity-100" @click="registry.unregister(ticket.id)">✕</button>
    </li>
  </ul>

  <p class="mt-2 text-xs opacity-50">{{ registry.size }} item{{ registry.size === 1 ? '' : 's' }}</p>
</template>
Warning

Don’t pass a registry directly to v-for. Pair events: true with useProxyRegistry() at the component boundary — the proxy exposes reactive keys, values, entries, and size properties that templates can iterate safely. Reading .values() from a reactive: true registry in a v-for breaks Vue’s dep tracking because the internal cache invalidates on every mutation.

Unlike events (which fire callbacks) or useProxyRegistry (which wraps with computed refs), reactive: true makes the underlying Map and each ticket shallowReactive. Use it when you need Vue’s dependency tracking at the ticket level.

useProxyModel for v-model Binding

When you need to sync a selection context with a v-model ref, use useProxyModel:

vue
<script setup lang="ts">
  import { createSelection, useProxyModel } from '@vuetify/v0'
  import { toRef } from 'vue'

  const model = defineModel({ default: 'blue' })

  const colors = [
    { id: 'red', value: 'red', hex: '#ef4444' },
    { id: 'blue', value: 'blue', hex: '#3b82f6' },
    { id: 'green', value: 'green', hex: '#22c55e' },
  ]

  const selection = createSelection({ events: true })
  selection.onboard(colors)

  useProxyModel(selection, model)

  const active = toRef(() => colors.find(c => c.value === model.value))
</script>

<template>
  <div class="flex gap-2">
    <button
      v-for="ticket in selection.values()"
      :key="ticket.id"
      class="size-8 rounded-full border-2 transition-all"
      :class="ticket.isSelected.value ? 'border-on-surface scale-110' : 'border-transparent'"
      :style="{ backgroundColor: colors.find(c => c.id === ticket.id)?.hex }"
      @click="ticket.select()"
    />
  </div>

  <p class="mt-2 text-sm">Selected: {{ active?.id ?? '—' }}</p>
</template>

Clicking a swatch calls ticket.select(), which updates model. Setting model.value = 'red' drives the selection back. Both directions stay in sync automatically.

useProxyRegistry for Full Reactivity

When you need automatic template updates for registry data, wrap it with useProxyRegistry:

ts
import { createRegistry, useProxyRegistry } from '@vuetify/v0'

const registry = createRegistry()

// Non-reactive: template won't update when items change
const items = registry.values()

// Reactive: changes trigger template updates automatically
const proxy = useProxyRegistry(registry)
// proxy.values is a computed ref that updates on any mutation

This pattern lets you choose reactivity granularity—pay for what you use

Events as Opt-In Reactivity

Registries emit events when operations occur. Use events to build reactive behavior only where needed:

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

const registry = createRegistry({ events: true })

// Listen for changes
registry.on('register:ticket', ticket => {
  console.log('Added:', ticket.id)
})

registry.on('unregister:ticket', ticket => {
  console.log('Removed:', ticket.id)
})

Available events:

  • register:ticket — Item added

  • unregister:ticket — Item removed

  • update:ticket — Item modified via upsert()

  • clear:registry — All items removed

  • reindex:registry — Indices recalculated

Naming Conventions

Composable names signal how they’re used:

create* — Factory Functions

Factory functions construct a new instance of stateful logic. They return an object you can provide, pass around, or destructure.

PatternExampleWhen to Use
Context factoriescreateContext, createTrinityBuilding reusable provide/inject pairs
State factoriescreateSelection, createRegistryCreating isolated state instances
Feature factoriescreateDataTable, createFormComposing multiple primitives into a feature

use* — Composables

Composables consume existing context or wrap browser APIs. They’re called inside setup() and return reactive state.

PatternExampleWhen to Use
Plugin consumersuseTheme, useLocale, useStorageReading app-level plugin state (requires plugin installation)
Browser wrappersuseEventListener, useResizeObserverSafe, lifecycle-managed browser API access
Behavior composablesuseHotkey, useClickOutsideAdding interactive behavior to elements

Foundation

Core factories that provide the foundation for all other composables.

NameDescription
createContextCreate reusable context to share state across components
createPluginCreate Vue plugins with standardized patterns
createTrinityCreate context provider/consumer pattern utilities

Registration

Collection management and data structure primitives.

NameDescription
createRegistryFoundation for registration-based systems
createQueueTime-based queue management with automatic timeouts
createTimelineBounded undo/redo system with fixed-size history
createTokensDesign token management system

Selection

State management for single and multi-selection patterns.

NameDescription
createModelValue store layer with disabled guards and apply bridge
createNestedHierarchical parent-child relationships with open/close state and tree traversal
createSelectionGeneral selection state management
createSingleSingle-selection with automatic deselection
createGroupMulti-selection with tri-state support
createStepSequential navigation for wizards and steppers

Forms

Form state management and model binding utilities.

NameDescription
createComboboxCoordinate selection, popover, virtual focus, and filtering for autocomplete
createFormForm validation coordinator
createInputShared form field primitive: validation, field state, ARIA IDs
createNumberFieldNumeric input state with formatting, parsing, and validation
createRatingBounded rating value with discrete items and half-step support
createSliderSlider state with multi-thumb support, step snapping, and value math
createValidationPer-field validation lifecycle

Reactivity

Reactive proxy utilities for bridging state.

NameDescription
useProxyModelBridge selection context to v-model binding
useProxyRegistryProxy-based registry with automatic reactivity

System

Browser API wrappers with automatic lifecycle cleanup.

NameDescription
useClickOutsideDetect clicks outside an element
useEventListenerHandle DOM events with automatic cleanup
useHotkeyHandle hotkey combinations and sequences
useImageImage loading state machine with deferred loading and retry
useIntersectionObserverIntersection Observer API for visibility detection
useLazyDefer rendering until first activation for dialogs, menus, and tooltips
useMediaQueryReactive CSS media query matching
useMutationObserverMutation Observer API for DOM change detection
usePopoverNative Popover API behavior with CSS anchor positioning
usePresenceAnimation-agnostic mount lifecycle with lazy mounting and exit timing
useRafScope-safe requestAnimationFrame with automatic cleanup
useResizeObserverResize Observer API for element size changes
useRovingFocusRoving tabindex keyboard navigation for composite widgets
useTimerReactive timer with pause/resume controls and remaining time tracking
useToggleScopeConditional effect scope management
useVirtualFocusVirtual focus for aria-activedescendant keyboard navigation patterns

Plugins

Application-level features installable via Vue plugins.

NameDescription
useBreakpointsResponsive breakpoint detection
useDateDate manipulation with Temporal API and locale-aware formatting
useFeaturesFeature flags and A/B testing
useHydrationSSR hydration management
useLocaleInternationalization system
useLoggerLogging system with multiple adapters
useNotificationsNotification lifecycle with toast queue and service adapter integration
usePermissionsRole-based access control
useRtlReactive RTL text direction with dir attribute management
useRulesValidation rule aliases with locale-aware messages
useStackOverlay z-index stacking with automatic calculation and scrim integration
useStorageReactive browser storage interface
useThemeTheme management with CSS custom properties

Data

Composables for filtering, sorting, paginating, and virtualizing collections.

NameDescription
createDataTableComposable data table with sort, filter, paginate, select, and expand
createFilterFilter arrays based on search queries
createPaginationPagination state with navigation methods
createVirtualVirtual scrolling for large lists

Semantic

Composables for presentational and semantic components.

NameDescription
createBreadcrumbsBreadcrumb navigation with path truncation
createOverflowCompute item capacity for responsive truncation
createProgressProgress tracking with multi-segment registration

Transformers

Value transformation utilities.

NameDescription
toArrayConvert any value to an array
toElementResolve refs, getters, or component instances to a plain DOM element
toReactiveConvert MaybeRef objects to reactive proxies
Was this page helpful?

© 2016-1970 Vuetify, LLC
Ctrl+/