Skip to main content
You are viewing Pre-Alpha documentation.
Vuetify0 Logo

Core

v0’s core architecture provides type-safe dependency injection and composable patterns. This page explains how v0 works. For creating plugins, see Plugins Guide.

Edit this page
Report a Bug
Copy Page as Markdown
AdvancedJan 11, 2026

Architecture Overview

Architecture Overview

Use controls to zoom and pan. Click outside or press Escape to close.

Architecture Overview

The Trinity Pattern

The signature pattern of v0. Every composable returns a readonly 3-tuple:

ts
const [useTheme, provideTheme, theme] = createThemeContext()

// 1. useTheme - Inject from ancestor
const theme = useTheme()

// 2. provideTheme - Provide to descendants
provideTheme()              // Use defaults
provideTheme(customTheme)   // Provide custom

// 3. theme - Direct access without DI
theme.cycle()  // Cycle through themes

Why Three Elements?

ElementPurpose
useContextConsume in child components
provideContextProvide from parent (defaults to built-in context)
defaultContextStandalone access, testing, outside Vue
Tip

The third element (defaultContext) is useful for unit testing without mounting Vue components.

createContext

Type-safe wrapper around Vue’s provide/inject that throws on missing context (no silent undefined):

Static Key Mode

ts
const [useTheme, provideTheme] = createContext<ThemeContext>('v0:theme')

// Provider
provideTheme({ isDark: ref(false), toggle: () => {} })

// Consumer - throws if not provided
const theme = useTheme()

Dynamic Key Mode

For nested contexts (panels within panels):

ts
const [usePanel, providePanel] = createContext<PanelContext>()

// Provider with runtime key
providePanel('panel-1', context)

// Consumer with same key
const panel = usePanel('panel-1')

Suffix Pattern

For parent-child context hierarchies:

ts
const [useItem, provideItem] = createContext<ItemContext>({ suffix: 'item' })

provideItem('v0:panel', context)  // Provides to 'v0:panel:item'
useItem('v0:panel')               // Injects from 'v0:panel:item'

Registry System

createRegistry is the foundational data structure. All selection, forms, and token composables extend it.

ts
const registry = createRegistry()

// Register items
const ticket = registry.register({ id: 'item-1', value: 'First' })

// Lookup
registry.get('item-1')      // Get by ID
registry.browse('First')    // Get IDs by value
registry.lookup(0)          // Get ID by index

// Cleanup
registry.unregister('item-1')

Ticket Structure

Every registered item is a “ticket”:

ts
interface RegistryTicket {
  id: ID,              // Unique identifier
  index: number,       // Position in registry
  value: unknown,      // Associated data
  valueIsIndex: boolean, // True if value wasn't explicitly set
}

Extension Chain

Extension Chain

Use controls to zoom and pan. Click outside or press Escape to close.

Extension Chain
ComposableExtendsAdds
createRegistryBase collection management
createSelectionRegistryselectedIds Set
createSingleSelectionSingle selection constraint
createGroupSelectionTri-state, batch ops
createStepSingleNavigation (next/prev/first/last)
createTokensRegistryAlias resolution
useFormRegistryValidation

Selection System

createSelection

Base multi-selection with Set-based tracking:

ts
const selection = createSelection({ multiple: true })

selection.register({ id: 'a', value: 'Apple' })
selection.register({ id: 'b', value: 'Banana' })

selection.select('a')
selection.selectedIds  // Set { 'a' }

createSingle

Auto-clears previous selection:

ts
const tabs = createSingle({ mandatory: true })

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

tabs.select('tab-1')
tabs.select('tab-2')  // tab-1 auto-unselected
tabs.selectedId.value // 'tab-2'

createGroup

Multi-select with tri-state:

ts
const checkboxes = createGroup()

checkboxes.onboard([
  { id: 'a', value: 'Option A' },
  { id: 'b', value: 'Option B' },
  { id: 'c', value: 'Option C' },
])

checkboxes.select(['a', 'b'])
checkboxes.selectAll()
checkboxes.isMixed.value  // true when some (not all) selected

createStep

Sequential navigation:

ts
const wizard = createStep({ circular: false })

wizard.onboard([
  { id: 'step-1', value: 'Step 1' },
  { id: 'step-2', value: 'Step 2' },
  { id: 'step-3', value: 'Step 3' },
])

wizard.first()  // Select first step
wizard.next()   // Move forward
wizard.prev()   // Move backward
wizard.last()   // Jump to end

Best Practices

Naming Conventions

PrefixPurposeExample
use*Inject from contextuseTheme()
create*Factory returning instancecreateSelection()
create*ContextFactory returning trinitycreateThemeContext()
create*PluginFactory returning Vue plugincreateThemePlugin()

When to Use Each

NeedUse
Share state in component treeprovideContext / useContext
App-wide singletoncreatePlugin with app.use()
Standalone logicDirect factory call
TestingTrinity’s third element
Ask AI
How do I handle scoped contexts for nested components without prop drilling?

© 2016-1970 Vuetify, LLC
Ctrl+/