Loading...
Loading...
Build with @vuetify/v0 headless composables and components for Vue 3. Use when creating selection state (single, multi, grouped, stepped), form validation, tab/dialog/popover UI, provide/inject context, registries, virtual scrolling, pagination, keyboard shortcuts, resize observers, theming, breakpoints, or SSR-safe browser detection. Triggers on v0, vuetify0, headless components, or WAI-ARIA patterns.
npx skill4agent add vuetifyjs/0 vuetify0@vuetify/v0 — Headless composables and components for Vue 3. Unstyled, logic-focused building blocks for design systems.
pnpm install @vuetify/v0import { createSelection } from '@vuetify/v0/composables'
import { Tabs } from '@vuetify/v0/components'
import { mergeDeep } from '@vuetify/v0/utilities'
import { IN_BROWSER } from '@vuetify/v0/constants'
import { Vuetify0DateAdapter } from '@vuetify/v0/date'
import type { ID } from '@vuetify/v0/types'claude mcp add --transport http vuetify-mcp https://mcp.vuetifyjs.com/mcpget_vuetify0_skillget_vuetify0_composable_listget_vuetify0_composable_guideget_vuetify0_component_listget_vuetify0_component_guide| Need | Use |
|---|---|
| Single item selection | |
| Multi-item selection | |
| Selection with "select all" | |
| Step wizard / carousel | |
| Tree / nested items | |
| Form validation | |
| Shared state (provide/inject) | |
| Collection tracking | |
| Overflow detection | |
| Stacking / z-index layers | |
| Filtering arrays | |
| Pagination | |
| Virtual scrolling | |
| Undo / redo | |
| Notification queue | |
| Design tokens | |
| Proxy model (v-model) | |
| Keyboard shortcuts | |
| Click outside | |
| Element resizing | |
| Element visibility | |
| Responsive breakpoints | |
| Theme switching | |
| Persistent storage | |
| SSR check | |
| Type guards | |
<script lang="ts" setup>
import { Tabs } from '@vuetify/v0/components'
</script>
<template>
<Tabs.Root v-model="active">
<Tabs.List>
<Tabs.Item value="overview">Overview</Tabs.Item>
<Tabs.Item value="features">Features</Tabs.Item>
</Tabs.List>
<Tabs.Panel value="overview">...</Tabs.Panel>
<Tabs.Panel value="features">...</Tabs.Panel>
</Tabs.Root>
</template><script lang="ts" setup>
import { Dialog } from '@vuetify/v0/components'
</script>
<template>
<Dialog.Root v-model="open">
<Dialog.Activator>Open</Dialog.Activator>
<Dialog.Content>
<Dialog.Title>Confirm</Dialog.Title>
<Dialog.Description>Are you sure?</Dialog.Description>
<Dialog.Close>Cancel</Dialog.Close>
</Dialog.Content>
</Dialog.Root>
</template>| Component | Purpose |
|---|---|
| Polymorphic element — render as any HTML tag |
| Image with fallback system |
| Checkbox with tri-state and group support |
| Modal with focus trap |
| Accordion (single or multi-expand) |
| Multi-selection container |
| Page navigation with First/Last/Next/Prev/Ellipsis |
| Toggle overlay (CSS anchor positioning) |
| Radio buttons with roving tabindex |
| Overlay backdrop |
| Generic selection container |
| Single-selection container |
| Stepper / wizard |
| Tab navigation with keyboard support |
// Single selection (e.g., theme picker, active tab)
const single = createSingle({ mandatory: 'force' })
single.register({ id: 'light', value: 'light' })
single.register({ id: 'dark', value: 'dark' })
single.select('dark')
single.selectedValue // Ref<string | undefined>
// Multi-selection (e.g., tag picker, multi-select list)
const selection = createSelection({ multiple: true })
selection.toggle('a')
selection.isSelected('a') // boolean
// Group with "select all" (e.g., data table checkboxes)
const group = createGroup()
group.selectAll()
group.toggleAll()
group.isMixed // true when partially selected
// Sequential navigation (e.g., stepper, carousel)
const stepper = createStep({ circular: true })
stepper.next()
stepper.prev()
stepper.first()
stepper.last()const form = createForm()
form.register({
id: 'email',
value: '',
rules: [
v => !!v || 'Required',
v => /.+@.+/.test(v) || 'Invalid email',
async v => await checkAvailable(v) || 'Email taken'
]
})
form.submit() // Validates all fields, returns { valid, errors }// createContext — type-safe provide/inject
const [useTheme, provideTheme] = createContext<ThemeContext>('Theme')
// Provider component
provideTheme({ mode, toggle })
// Consumer component (throws helpful error if not provided)
const { mode, toggle } = useTheme()
// createTrinity — context with built-in defaults
const [useConfig, provideConfig, defaultConfig] = createTrinity<Config>('Config', {
theme: 'light',
locale: 'en'
})// Filtering
const { apply } = createFilter({ keys: ['name', 'email'] })
const filtered = apply(query, users)
// Pagination
const pagination = createPagination({ page: 1, itemsPerPage: 10, length: 100 })
pagination.next()
// Virtual scrolling
const { virtualItems, totalHeight, scrollTo } = createVirtual({
items: largeList,
itemHeight: 48
})
// Undo/redo
const timeline = createTimeline({ maxSize: 50 })
timeline.push(state)
timeline.undo()
// Notification queue with auto-dismiss
const notifications = createQueue({ timeout: 5000 })
notifications.push({ message: 'Saved!' })// SSR-safe environment checks
import { IN_BROWSER, SUPPORTS_TOUCH, SUPPORTS_OBSERVER } from '@vuetify/v0/constants'
// DOM observation (auto-cleanup on unmount)
const { width, height } = useResizeObserver(el)
const { isIntersecting } = useIntersectionObserver(el, { threshold: 0.1 })
// Events
useEventListener(window, 'resize', onResize)
useHotkey('ctrl+k', openSearch)
useClickOutside(menuRef, close)
// Responsive
const { md, lgAndUp } = useBreakpoints()
const { matches } = useMediaQuery('(prefers-color-scheme: dark)')main.tsimport { createThemePlugin, createBreakpointsPlugin } from '@vuetify/v0'
app.use(
createThemePlugin({
themes: {
light: { colors: { primary: '#3b82f6' } },
dark: { colors: { primary: '#60a5fa' } },
}
})
)
app.use(createBreakpointsPlugin())
// Then in any component:
const { current, toggle } = useTheme()
const { md, lgAndUp } = useBreakpoints()createThemePlugincreateBreakpointsPlugincreateFeaturesPlugincreateLoggerPlugincreateLocalePlugincreateDatePlugincreateStoragePlugin// Bad — v0 handles reactivity, mandatory constraints, and events for you
const selected = ref<string[]>([])
function toggle (id: string) {
const index = selected.value.indexOf(id)
if (index >= 0) selected.value.splice(index, 1)
else selected.value.push(id)
}
// Good
const selection = createSelection({ multiple: true })
selection.toggle(id)// Bad — no type safety, no error on missing provider
provide('theme', theme)
const theme = inject('theme') // Could be undefined!
// Good — type-safe, throws descriptive error if provider is missing
const [useTheme, provideTheme] = createContext<ThemeContext>('theme')// Bad
if (typeof window !== 'undefined')
// Good
import { IN_BROWSER } from '@vuetify/v0/constants'
if (IN_BROWSER)Foundation (no dependencies)
├── createContext → Basic DI
├── createPlugin → Vue plugin factory
└── createTrinity → [use, provide, default] pattern
Registry (uses Foundation)
├── createRegistry → Collection management
├── useProxyRegistry → External registry proxy
└── useStack → Layered z-index management
Selection (uses Registry)
├── createSelection → Multi-select (base)
├── createSingle → Single-select
├── createGroup → Multi + tri-state
├── createStep → Sequential navigation
└── createNested → Hierarchical
Data (uses Registry)
├── createForm → Validation
├── createFilter → Array filtering
├── createPagination → Page navigation
├── createVirtual → Virtual scrolling
├── createTokens → Design tokens
├── createQueue → FIFO with timeout
└── createTimeline → Undo/redo
System (standalone)
├── useResizeObserver → Element dimensions
├── useIntersectionObserver → Visibility detection
├── useMutationObserver → DOM mutations
├── useEventListener → Auto-cleanup events
├── useHotkey → Keyboard shortcuts
├── useClickOutside → Outside click detection
├── useToggleScope → Conditional effect scopes
└── createOverflow → Container overflow detection
Plugins (app-wide, uses createPlugin)
├── useTheme → Theme switching
├── useBreakpoints → Responsive detection
├── useLocale → i18n
├── useDate → Date utilities
├── useStorage → localStorage/sessionStorage
├── useFeatures → Feature flags
├── usePermissions → Permission management
├── useLogger → Logging
├── useHydration → SSR hydration
└── useLazy → Deferred computation
Transformers
├── toArray → Normalize to array
└── toReactive → MaybeRef to reactiveimport { mergeDeep, clamp, range, debounce, useId } from '@vuetify/v0/utilities'
mergeDeep({}, defaults, overrides) // Deep merge (prototype-pollution safe)
clamp(value, 0, 100) // Clamp to range
range(5) // [0, 1, 2, 3, 4]
range(5, 1) // [1, 2, 3, 4, 5]
const search = debounce(fn, 300) // With .clear() and .immediate()
const id = useId() // SSR-safe unique IDimport { isString, isNumber, isObject, isArray, isFunction, isBoolean, isNull, isUndefined, isNullOrUndefined, isPrimitive, isSymbol, isNaN } from '@vuetify/v0/utilities'