createRegistry
Foundation for ordered, keyed collections. Items are registered with IDs and indexes, and can be looked up by ID, index, or value.
Usage
The createRegistry composable provides a powerful interface for managing collections of items in a registration-based system. It allows you to register, unregister, and look up items efficiently, while maintaining an index for quick access.
import { createRegistry } from '@vuetify/v0'
import type { RegistryTicket } from '@vuetify/v0'
interface Item extends RegistryTicket<string> {
label: string
}
const registry = createRegistry<Item>()
// Register individual items
const a = registry.register({ label: 'Alpha' })
const b = registry.register({ label: 'Beta' })
const c = registry.register({ label: 'Gamma' })
console.log(registry.size) // 3
console.log(a.index) // 0
// Look up by id
const found = registry.get(b.id)
console.log(found?.label) // 'Beta'
// Patch a field without replacing the ticket
registry.upsert(b.id, { label: 'Beta (updated)' })
// Move to a new position
registry.move(a.id, 2)
console.log(a.index) // 2
// Remove one
registry.unregister(c.id)
console.log(registry.size) // 2
// Bulk load
registry.onboard([
{ id: 'x', label: 'X' },
{ id: 'y', label: 'Y' },
])
// Bulk remove
registry.offboard(['x', 'y'])Context / DI
Use createRegistryContext to share a registry across a component tree:
import { createRegistryContext } from '@vuetify/v0'
export const [useItems, provideItems, items] =
createRegistryContext({ namespace: 'my:items' })
// In parent component
provideItems()
// In child component
const registry = useItems()
registry.register({ id: 'item-1', value: 'First' })Architecture
createRegistry is the foundation for specialized registration systems:
Each branch extends the base ticket pattern with domain-specific capabilities. See individual composable docs for their extension hierarchies.
Reactivity
createRegistry uses minimal reactivity by default for performance. Collection methods are not reactive unless you opt in.
| Method | Notes |
|---|---|
register(ticket) | Append a ticket to the registry; a supplied index is ignored — use move() to position |
unregister(id) | Remove a ticket by ID |
upsert(id, partial) | Register or update a ticket |
move(id, index) | Move a ticket to a new index position; reindexes only the affected [from..to] span |
reorder(ids) | Reorder the registry to match a canonical permutation in one O(n) pass |
onboard(tickets) | Batch-register an array of tickets |
offboard(ids) | Batch-unregister an array of IDs |
batch(fn) | Run multiple mutations with deferred cache invalidation and events |
get(id) | Retrieve a ticket by ID |
has(id) | Check whether a ticket ID is registered |
browse(value) | Reverse-lookup — find ticket ID(s) by value |
lookup(index) | Find ticket ID by zero-based index |
seek(direction, from?, predicate?) | Find 'first' or 'last' ticket, optionally starting from an index and/or filtered by predicate |
keys() | All registered IDs as a readonly array |
values() | All registered tickets as a readonly array |
entries() | All [id, ticket] pairs as a readonly array |
clear() | Remove all tickets |
dispose() | Remove all tickets and clear event listeners |
Need reactive collections? Pass { reactive: true } to make keys(), values(), entries(), size, and per-ticket field reads reactive in templates and computeds. Upserts on existing tickets propagate through the shallowReactive wrapping. For event-driven snapshots — or when you want deep: true tracking or need reactivity without wrapping the tickets themselves — use useProxyRegistry with { events: true }.
Examples
Event log
+ Registered "Set up CI pipeline"
+ Registered "Write unit tests"
+ Registered "Update README"
+ Registered "Review PR #42"
+ Registered "Refactor auth module"
FAQ
register always appends to the end. A supplied index is intentionally ignored — call move(id, index) after registering to reposition a ticket, which reindexes only the affected span.
createRegistry uses minimal reactivity by default for performance. Pass { reactive: true } to make keys(), values(), entries(), size, and per-ticket field reads reactive in templates and computeds.
createRegistry is the base ordered, keyed collection — registration, indexing, and lookup. createSelection extends it (through createModel) with selection state. Use createRegistry when you need to track items but not which are selected.
Pass { reactive: true } to make keys(), values(), entries(), size, and per-ticket field reads reactive directly on the registry. Reach for useProxyRegistry when you want event-driven snapshots, deep: true tracking, or reactivity without wrapping the tickets themselves.
Wrap them in batch(fn). It defers cache invalidation and event emission until the callback finishes, so a sequence of register / move / unregister calls settles once instead of per-mutation.
Each unregister does an O(n) scan to locate and splice the ticket, so tearing down N tickets individually — a parent unmounting hundreds of registered children, for example — is O(n²). Batch removals through offboard(ids) or clear(), which compact in a single pass, and keep the mounted (and therefore registered) count bounded with createVirtual for large lists.
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.