Two-Way Binding to More Than One Prop
Multiple v-model
A single component can expose multiple v-model targets by name, letting it bind two or more independent values at once.
What you'll learn
- Define multiple named defineModel calls
- Bind them with v-model:name on the parent
- Build a date-range component
For components that wrap several values, you can declare more than one defineModel. Each takes a name; the parent binds it with v-model:name.
Named Models
<!-- DateRange.vue -->
<script setup lang="ts">
const start = defineModel<string>('start')
const end = defineModel<string>('end')
</script>
<template>
<input type="date" :value="start" @change="start = ($event.target as HTMLInputElement).value" />
<input type="date" :value="end" @change="end = ($event.target as HTMLInputElement).value" />
</template> The parent binds each one independently:
<script setup lang="ts">
import { ref } from 'vue'
import DateRange from './DateRange.vue'
const from = ref('2026-01-01')
const to = ref('2026-12-31')
</script>
<template>
<DateRange v-model:start="from" v-model:end="to" />
<p>{{ from }} → {{ to }}</p>
</template> Mixing With a Default
You can mix the default (unnamed) model with named ones:
<script setup lang="ts">
const value = defineModel<string>() // default
const error = defineModel<string>('error') // named
</script> The parent then writes <Field v-model="text" v-model:error="err" />.
Why Bother
Named models keep things readable when a component naturally has multiple related values. Common shapes:
- DateRange: start and end
- Pagination: page and pageSize
- LatLng picker: lat and lng
- ColorPicker: hue, saturation, lightness
Each one stays a small, independent piece of state — no awkward object you have to spread on every change.
Basic Form Validation →