You are viewing Pre-Alpha documentation. Some features may not work as expected.
Composables
Composables are the foundation of v0. They provide headless logic that you can use directly or through wrapper components.
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 When | Use Components When |
|---|---|
| Need full control over rendering | Want declarative templates |
| Building custom abstractions | Standard UI patterns |
| Non-DOM contexts (stores, workers) | Accessibility attrs needed |
| Maximum flexibility | Faster development |
Categories
Foundation
Factories that create other composables:
| Composable | Purpose |
|---|---|
| createContext→ | Type-safe provide/inject |
| createTrinity→ | [use, provide, context] tuple |
| createPlugin→ | Vue plugin factory |
Registration
Collection management primitives:
| Composable | Purpose |
|---|---|
| useRegistry→ | Base collection with lookup |
| useTokens→ | Design token aliases |
| useQueue→ | Time-based queue |
| useTimeline→ | Undo/redo history |
Selection
State management for selection patterns:
| Composable | Purpose |
|---|---|
| useSelection→ | Multi-select base |
| useSingle→ | Radio, tabs, accordion |
| useGroup→ | Checkboxes, tri-state |
| useStep→ | Wizard, stepper, carousel |
Forms
Form state and validation:
| Composable | Purpose |
|---|---|
| useForm→ | Validation, dirty tracking |
| useProxyModel→ | v-model bridge |
Plugins
App-level features installed via app.use():
| Composable | Purpose |
|---|---|
| useTheme→ | Dark/light mode |
| useLocale→ | i18n, RTL |
| useBreakpoints→ | Responsive queries |
| useStorage→ | Persistent state |
Utilities
Standalone helpers:
| Composable | Purpose |
|---|---|
| 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