How to handle multiple v-model bindings in Vue

Handling multiple v-model bindings in Vue enables complex component APIs with multiple synchronized properties for advanced form controls and interactive components. As the creator of CoreUI, a widely used open-source UI library, I’ve implemented multiple v-model bindings in sophisticated components like date range pickers and multi-select controls. From my expertise, the most effective approach is using named v-model directives with defineModel for clean component APIs. This method provides multiple two-way data binding channels while maintaining clear separation of concerns for different properties.

Use named v-model directives with defineModel to handle multiple synchronized properties.

<!-- UserEditor.vue (child component) -->
<template>
  <div class="user-editor">
    <input
      v-model="firstName"
      placeholder="First Name"
      @input="updateFirstName">

    <input
      v-model="lastName"
      placeholder="Last Name"
      @input="updateLastName">

    <input
      v-model="email"
      type="email"
      placeholder="Email"
      @input="updateEmail">

    <select v-model="role" @change="updateRole">
      <option value="user">User</option>
      <option value="admin">Admin</option>
      <option value="moderator">Moderator</option>
    </select>
  </div>
</template>

<script setup>
// Define multiple v-models
const firstName = defineModel('firstName', { default: '' })
const lastName = defineModel('lastName', { default: '' })
const email = defineModel('email', { default: '' })
const role = defineModel('role', { default: 'user' })

const updateFirstName = () => {
  // Additional validation or formatting logic
  firstName.value = firstName.value.trim()
}

const updateLastName = () => {
  lastName.value = lastName.value.trim()
}

const updateEmail = () => {
  email.value = email.value.toLowerCase().trim()
}

const updateRole = () => {
  // Role change logic
  console.log('Role changed to:', role.value)
}
</script>

<!-- Parent component usage -->
<template>
  <UserEditor
    v-model:first-name="user.firstName"
    v-model:last-name="user.lastName"
    v-model:email="user.email"
    v-model:role="user.role" />

  <div>
    <h3>User Data:</h3>
    <p>Name: {{ user.firstName }} {{ user.lastName }}</p>
    <p>Email: {{ user.email }}</p>
    <p>Role: {{ user.role }}</p>
  </div>
</template>

<script setup>
import { reactive } from 'vue'

const user = reactive({
  firstName: 'John',
  lastName: 'Doe',
  email: '[email protected]',
  role: 'user'
})
</script>

Named v-model directives use the v-model:propertyName syntax to bind specific properties. The defineModel composable creates reactive references that automatically sync with parent component data. Each v-model creates a two-way binding channel for independent property synchronization.

Best Practice Note:

This is the same multiple v-model approach we use in CoreUI Vue components for complex form controls. Use descriptive names for each v-model binding and provide default values to ensure robust component initialization and prevent undefined states.


Speed up your responsive apps and websites with fully-featured, ready-to-use open-source admin panel templates—free to use and built for efficiency.


About the Author

Subscribe to our newsletter
Get early information about new products, product updates and blog posts.
What is the Difference Between Null and Undefined in JavaScript
What is the Difference Between Null and Undefined in JavaScript

What is the difference between typeof and instanceof in JavaScript
What is the difference between typeof and instanceof in JavaScript

How to Convert a Map to an Array in JavaScript
How to Convert a Map to an Array in JavaScript

How to Add a Tab in HTML
How to Add a Tab in HTML

Answers by CoreUI Core Team