Skip to main content
You are viewing Pre-Alpha documentation.
Vuetify0 Logo
Theme
Mode
Accessibility
Vuetify
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

createModel

Manage a reactive value with two-way sync — wrap a ref in a model and useProxyModel keeps it in sync automatically.

Usage

createModel stores a reactive value. Register a ref and useProxyModel keeps it synced — the same idea as defineModel but built on the registry pattern.

ts
import { shallowRef } from 'vue'
import { createModel, useProxyModel } from '@vuetify/v0'

const value = shallowRef<string>()
const model = createModel()

model.register({ id: 'fruit', value })
// ticket is already selected — enroll defaults to true

useProxyModel(model, value)

Tickets are enrolled on registration by default (enroll: true). With single-value semantics, only the most recently registered ticket is active. Pass enroll: false to opt out.

Most of the time you register a single ticket — that’s the only value you care about. The registry pattern underneath gives you the ability to compose multiple values into a compound model when you need it, which is what createSelection builds on.

Pass multiple: true to let select() accumulate IDs instead of clearing first. This is how createSlider keeps all thumbs selected simultaneously. Selection-specific concepts like mandatory belong in createSelection. Both composables accept enroll, but createSelection defaults it to false.

Architecture

createModel sits between createRegistry and the higher-level composables:

Model Hierarchy

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

Model Hierarchy

Reactivity

Value state is always reactive. Collection methods follow the base createRegistry pattern.

Property/MethodReactiveNotes
selectedIdsshallowReactive(Set) — always reactive
selectedItemsComputed from selectedIds
selectedValuesComputed from selectedItems, unwraps refs via toValue
ticket isSelectedComputed from selectedIds
Tip

Value vs Collection Most UI patterns only need value reactivity (which is always on). You rarely need the collection itself to be reactive.

Examples

Compound Value

A model isn’t limited to one value. Register multiple tickets — each with its own ref and input type — and the model composes them into a single compound output. The compound output at the bottom is a toRef over selectedValues, so it updates whenever a ticket’s value changes or a ticket is toggled in or out of the composition.

Data Flow

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

Data Flow

Each ticket’s value can be any type: a string, a number, an array. The checkbox next to each ticket controls whether it’s included in the compound. Disabling a ticket freezes its value and prevents selection changes. Because each value is a ref, edits flow through the model reactively — type in the text field, pick a radio, check a topping, or drag the slider and the compound reflects the change immediately.

This pattern is the foundation for compound inputs like forms, filters, and configuration panels — anywhere multiple independent values need to be composed into a single reactive output.

FileRole
createCompound.tsCreates the model, registers four tickets with typed refs, exports reactive compound
compound.vueRenders each ticket with its matching input control, toggles composition membership
0 / 4 in compound
name
size
toppings
quantity
2
Compound Value
[]

Color Palette

This example uses createSelection (which extends createModel) to compose a palette from five OKLCH hue values. Each color is a ticket with a ref(hue) as its value — the hue sliders write directly to those refs, so dragging a slider shifts the color in real time without any re-registration.

Data Flow

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

Data Flow

The circle next to each color toggles it in or out of the composition. Purple is registered with disabled: true, so it can’t be toggled or adjusted. The composite strip at the bottom renders only the active colors as equal-width segments, with degree labels underneath.

The provider/consumer split keeps the model definition (model.ts) separate from the UI (ColorConsumer.vue). The provider creates the model and provides it via createContext; the consumer injects it and renders the controls. This is the same pattern you’d use in a real application to share model state across a component tree.

FileRole
model.tsCreates the selection, registers five OKLCH colors with ref(hue) values, exports context tuple
ColorProvider.vueCalls createColorModel() and provides context via slot
ColorConsumer.vueInjects context, renders hue sliders with gradient tracks and composite strip
colors.vueEntry point composing Provider around Consumer
Palette4 / 5
red
15°
blue
245°
green
155°
purple
290°
orange
55°
Composite
15° 245° 155° 55°
[
  15,
  245,
  155,
  55
]

API Reference

The following API details are for the createModel composable.

Functions

createModel

(_options?: ModelOptions) => R

Creates a new model instance for storing a single value.

Options

events

boolean | undefined

Enable event emission for registry operations

Default: false

reactive

boolean | undefined

Enable reactive behavior for registry operations

Default: false

disabled

MaybeRefOrGetter<boolean> | undefined

Disabled state for the entire model instance

Default: false

enroll

MaybeRefOrGetter<boolean> | undefined

Auto-select tickets on registration

Default: true

multiple

MaybeRefOrGetter<boolean> | undefined

Allow multiple tickets to be selected simultaneously

Default: false

Properties

collection

ReadonlyMap<ID, E>

The collection of tickets in the registry

size

number

The number of tickets in the registry

selectedIds

Reactive<Set<ID>>

Set of currently selected ticket IDs

selectedItems

ComputedRef<Set<E>>

Computed Set of selected ticket instances

selectedValues

ComputedRef<Set<E["value"] extends Ref<infer U, infer U> ? U : E["value"]>>

Computed Set of selected ticket values

disabled

MaybeRefOrGetter<boolean>

Disabled state for the entire model instance

Methods

clear

() => void

Clear the entire registry

has

(id: ID) => boolean

Check if a ticket exists by ID

keys

() => readonly ID[]

Get all registered IDs

browse

(value: E["value"]) => ID[] | undefined

Browse for an ID(s) by value

lookup

(index: number) => ID | undefined

lookup a ticket by index number

get

(id: ID) => E | undefined

Get a ticket by ID

upsert

(id: ID, ticket?: Partial<Z>) => E

Update or insert a ticket by ID

values

() => readonly E[]

Get all values of registered tickets

entries

() => readonly [ID, E][]

Get all entries of registered tickets

unregister

(id: ID) => void

Unregister a ticket by ID

reindex

() => void

Reset the index directory and update all tickets

move

(id: ID, toIndex: number) => E | undefined

Seek for a ticket based on direction and optional predicate

seek

(direction?: "first" | "last", from?: number, predicate?: (ticket) => boolean) => E | undefined

on

<K extends Extensible<RegistryEventName>>(event: K, cb: EventHandler<E, K>) => void

Listen for registry events

off

<K extends Extensible<RegistryEventName>>(event: K, cb: EventHandler<E, K>) => void

Stop listening for registry events

emit

<K extends Extensible<RegistryEventName>>(event: K, data: EventPayload<E, K>) => void

Emit an event with data

dispose

() => void

Clears the registry and removes all listeners

onboard

(registrations: Partial<Z & RegistryTicket>[]) => E[]

Onboard multiple tickets at once

offboard

(ids: ID[]) => void

Offboard multiple tickets at once

batch

<R>(fn: () => R) => R

Execute operations in a batch, deferring cache invalidation and event emission until complete

reset

() => void

Reset selection state without destroying the registry

select

(id: ID) => void

Select a ticket by ID

unselect

(id: ID) => void

Unselect a ticket by ID

toggle

(id: ID) => void

Toggle a ticket's selection state

selected

(id: ID) => boolean

Check if a ticket is currently selected

apply

(values: unknown[], options?: { multiple?) => void

Apply external values to the model

register

(registration?: Partial<Z>) => E

Register a new ticket

Benchmarks

Every operation is profiled across multiple dataset sizes to measure real-world throughput. Each benchmark is assigned a performance tier—good, fast, blazing, or slow—and groups are scored by averaging their individual results so you can spot bottlenecks at a glance. This transparency helps you make informed decisions about which patterns scale for your use case. Learn more in the benchmarks guide.

View benchmark source↗

Was this page helpful?

© 2016-1970 Vuetify, LLC
Ctrl+/