You are viewing Pre-Alpha documentation.
Vuetify0 Logo

Composables

Composables are the foundation of v0. They provide headless logic that you can use directly or through wrapper components.

Edit this page
Report a Bug
Copy Page as Markdown

Composables vs Components

Both approaches use the same underlying logic:

ts
// Direct composable usage
const selection = createSelection({ multiple: true })
selection.register({ id: 'a', value: 'Apple' })
selection.select('a')
vue
<template>
  <Selection.Root v-model="selected" multiple>
    <Selection.Item value="Apple">Apple</Selection.Item>
  </Selection.Root>
</template>

When to Use Each

Use Composables WhenUse Components When
Need full control over renderingWant declarative templates
Building custom abstractionsStandard UI patterns
Non-DOM contexts (stores, workers)Accessibility attrs needed
Maximum flexibilityFaster development

Categories

Foundation

Factories that create other composables:

ComposablePurpose
createContext→Type-safe provide/inject
createTrinity→[use, provide, context] tuple
createPlugin→Vue plugin factory

Registration

Collection management primitives:

ComposablePurpose
useRegistry→Base collection with lookup
useTokens→Design token aliases
useQueue→Time-based queue
useTimeline→Undo/redo history

Selection

State management for selection patterns:

ComposablePurpose
useSelection→Multi-select base
useSingle→Radio, tabs, accordion
useGroup→Checkboxes, tri-state
useStep→Wizard, stepper, carousel

Forms

Form state and validation:

ComposablePurpose
useForm→Validation, dirty tracking
useProxyModel→v-model bridge

Plugins

App-level features installed via app.use():

ComposablePurpose
useTheme→Dark/light mode
useLocale→i18n, RTL
useBreakpoints→Responsive queries
useStorage→Persistent state

Utilities

Standalone helpers:

ComposablePurpose
useFilter→Array filtering
usePagination→Page navigation
useVirtual→Virtual scrolling

Usage Patterns

Direct Factory Call

For standalone instances:

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

const tabs = createSelection({ multiple: false })
tabs.register({ id: 'home', value: 'Home' })
tabs.register({ id: 'about', value: 'About' })
tabs.select('home')

Context Injection

For component tree sharing:

ts
// Parent
import { createSelectionContext } from '@vuetify/v0'

const [useSelection, provideSelection] = createSelectionContext({
  namespace: 'tabs'
})
provideSelection({ multiple: false })

// Child
const selection = useSelection('tabs')
selection.select('home')

Plugin Installation

For app-wide singletons:

ts
import { createApp } from 'vue'
import { createThemePlugin } from '@vuetify/v0'

const app = createApp(App)
app.use(createThemePlugin({
  defaultTheme: 'light',
  themes: { light: {...}, dark: {...} }
}))

Composing Composables

Build complex behavior by combining primitives:

ts
import { createSelection, useFilter, createPagination } from '@vuetify/v0'

// Filterable, paginated selection
const items = ref([...])
const filter = useFilter(items)
const pagination = createPagination({
  size: () => filter.filtered.value.length,
  itemsPerPage: 10
})
const selection = createSelection({ multiple: true })

// Visible items with selection state
const visibleItems = computed(() => {
  const start = pagination.pageStart.value
  const end = pagination.pageStop.value
  return filter.filtered.value.slice(start, end)
})

TypeScript

All composables are fully typed:

ts
interface MyItem {
  id: string
  label: string
  disabled?: boolean
}

const selection = createSelection<MyItem>()
selection.register({ id: '1', value: { id: '1', label: 'First' } })

// Type-safe access
const item = selection.get('1')
item?.value.label // string

© 2016-2025 Vuetify, LLC
Ctrl+/