Multiple v-model

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.

4 min read Level 2/5 #vue#forms
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 →