use-v-model
Two-way binding helper for a component prop.
| Package | @vizejs/composable/use-v-model |
| Own the source | vize lib pull composable:use-v-model |
| Runtime exports | useVModel, useVModels |
| Gzip budget | 1024 B |
Minimal setup
Use a Vue 3.5+ project with Vue SFC compilation configured (see Vite+ integration).
vp install @vizejs/composable
Import the entry directly. Call lifecycle-bound utilities inside <script setup> so cleanup follows the component scope; consult the runtime contract for this entry's SSR and hydration behavior.
import { useVModel, useVModels } from "@vizejs/composable/use-v-model";
Try it
Support v-model with a local fallback
Write a component whose value can be bound with v-model but still works when no parent binds it.
What to observe: Type a nickname and the greeting updates, even though nothing binds v-model in this preview.
With passive: true the component keeps a local copy and emits update:modelValue; a parent that binds v-model stays the source of truth.
Compare the initial and interacted states


Copy the example
Save this complete SFC in your Vue project. Its public imports and source are the same ones executed in the preview.
<script setup lang="ts">
import { useVModel } from "@vizejs/composable/use-v-model";
const props = defineProps<{ modelValue?: string }>();
const emit = defineEmits<{ "update:modelValue": [value: string | undefined] }>();
const nickname = useVModel(props, "modelValue", emit, { passive: true, defaultValue: "Ada" });
</script>
<template>
<div class="composable-example">
<p>
Write a component that works with <code>v-model</code> and also keeps its own value when no
parent binds one.
</p>
<label>
Nickname
<input v-model="nickname" />
</label>
<output aria-live="polite">Hello, {{ nickname }}!</output>
</div>
</template>
Runtime contract
| Utility | Category | Stability | SSR | Hydration | Cleanup | Targets | Host globals | Uses |
|---|---|---|---|---|---|---|---|---|
useVModel |
reactivity | experimental | safe | stable | reactive-scope | web, server, worker, native, desktop, terminal | structuredClone |
— |
useVModels |
reactivity | experimental | safe | stable | reactive-scope | web, server, worker, native, desktop, terminal | structuredClone |
useVModel |
API
useVModel
Two-way binding helper for a component prop. Reads the prop and emits update:<key> (or eventName) on write, typed end to end: the key must be a prop, the emitted value has the prop's type, and emit must accept that exact event (a defineEmits result with the matching overload qualifies). With passive: true a local ref mirrors the prop so the component also works uncontrolled. Relies only on the props and emit you pass (no component internals), so it is SSR- and Vapor-friendly; the passive watchers follow the owning scope.
function useVModel< Props extends object, Key extends keyof Props & string, Event extends string = `update:${Key}`, Default extends Exclude<Props[Key], undefined> | undefined = undefined, >( props: Props, key: Key, emit: VModelEmit<NoInfer<Event>, NoInfer<Props[Key]>>, options?: UseVModelOptions<Props[Key], Event, Default>, ): Ref<VModelValue<Props[Key], Default>>
const props = defineProps<{ modelValue: string }>();
const emit = defineEmits<{ "update:modelValue": [value: string] }>();
const model = useVModel(props, "modelValue", emit);
model.value = "next"; // emits update:modelValue
useVModel
function useVModel( props: Readonly<Record<string, unknown>>, key: string, emit: VModelEmit<string, unknown>, options: UseVModelOptions<unknown, string, unknown> = {}, ): Ref<unknown> | WritableComputedRef<unknown>
useVModels
useVModel for several props at once. Returns one writable ref per bound prop, each emitting its own update:<prop> event. emit must declare an update event for every bound key; restrict the set with keys.
function useVModels< Props extends object, const Key extends keyof Props & string = keyof Props & string, >( props: Props, emit: NoInfer<VModelsEmit<Props, Key>>, options?: UseVModelsOptions<Key>, ): { readonly [Name in Key]: Ref<Props[Name]> }
const { open, value } = useVModels(props, emit, { keys: ["open", "value"] });
useVModels
function useVModels( props: Readonly<Record<string, unknown>>, emit: VModelEmit<`update:${string}`, unknown>, options: UseVModelsOptions<string> = {}, ): { readonly [key: string]: Ref<unknown> }
Types
UseVModelOptions
Options for useVModel.
| Member | Type | Description |
|---|---|---|
passive? |
boolean |
Keep a local copy that works even when the parent does not bind v-model: writes update the copy and emit, prop changes overwrite it. |
eventName? |
Event |
Event name to emit. |
deep? |
boolean |
In passive mode, store the local copy deeply reactive and also emit on nested mutations of it. |
defaultValue? |
Default |
Value read while the prop is undefined. |
clone? |
boolean | ((value: Value) => Value) |
In passive mode, copy prop values before storing them locally so local mutations never touch the parent's object: true uses structuredClone on the raw (unproxied) value, a function is used as the cloner. |
shouldEmit? |
(value: Value) => boolean |
Veto emitting a value. |
UseVModelsOptions
Options for useVModels.
| Member | Type | Description |
|---|---|---|
keys? |
readonly Key[] |
Props to bind. Defaults to every prop, which then requires an update:<prop> emit for each of them. |