How to use v-model in Vue 3?

How to use v-model in Vue 3?

In Vue 3, the v-model has been completely changed and is no longer compatible with the Vue 2 syntax. In this article, I will explain how to use the v-model in Vue 3, and what new functionality it brings. Before I do that, let's quickly look at the old syntax.

Old v-model syntax in Vue 2

Let's say we have a Parent component that contains a custom TextField component:

// ParentComponent.vue
<template>
  <TextField v-model="providedUsername" />
</template>

<script>
import TextField from "./TextField";

export default {
  name: "ParentComponent",
  components: {
    TextField
  },
  data: function() {
    return {
      providedUsername: null,
    };
  },
};
</script>

The TextField component is compatible with v-model because it uses the value property and emits the input event:

// TextField.vue
<template>
  <input type="text" :value="value" @input="$emit('input', $event.target.value)" />
</template>

<script>
export default {
  name: "TextField",
  props: {
    value: String
  }
};
</script>

New v-model  in Vue 3

Now, let's see how to use the v-model in Vue 3. Let's start with the parent component. The main change in Vue 3 is that instead of the data  function, we use the setup() to define a reference to the username field:

// ParentComponent.vue
<template>
  <TextField v-model="providedUsername" />
</template>

<script>
import { ref } from "vue";
import TextField from "./TextField";

export default {
  name: "ParentComponent",
  components: {
    TextField
  },
  setup() {
    const providedUsername = ref(null);
    
    return { providedUsername };
  }
};
</script>

Now, let's define the TextField component:

// TextField.vue
<template>
  <input type="text" :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" />
</template>

<script>
export default {
  name: "TextField",
  props: {
    modelValue: {
      type: String
    }
  }
};
</script>

The big change is that for the v-model we no longer use the value property. Instead, in Vue 3, we use the modelValue. A similar situation is with the event. Instead of the input event,  we emit the update:modelValue.

In summary, to migrate v-model from Vue 2 to Vue 3 rename :

  • prop: value -> modelValue
  • event: input -> update:modelValue

Custom v-model argument

Vue 3 allows to easily use a custom property name with v-model.  Let's say we want to use a username property. In that case, the parent component will look like this:

// ParentComponent.vue
<template>
  <TextField v-model:username="providedUsername" />
</template>

<script>
import { ref } from "vue";
import TextField from "./TextField";

export default {
  name: "ParentComponent",
  components: {
    TextField
  },
  setup() {
    const providedUsername = ref(null);
    
    return { providedUsername };
  }
};
</script>

To make the TextField work with the v-model, all we have to do is update the property and event by replacing the modelValue with username:

// TextField.vue
<template>
  <input type="text" :value="username" @input="$emit('update:username', $event.target.value)" />
</template>

<script>
export default {
  name: "TextField",
  props: {
    username: {
      type: String
    }
  }
};
</script>

Multiple v-models in one component

Another new feature of Vue 3 is the ability to use multiple v-models in one component:

// ParentComponent.vue
<template>
  <LoginForm v-model:username="providedUsername" v-model:password="providedPassword" />
</template>

<script>
import { ref } from "vue";
import LoginForm from "./LoginForm";

export default {
  name: "ParentComponent",
  components: {
    LoginForm
  },
  setup() {
    const providedUsername = ref(null);
    const providedPassword = ref(null);
    
    return { providedUsername, providedPassword };
  }
}
</script>
// LoginForm.vue
<template>
  <form>
    <input type="text" :value="username" @input="$emit('update:username', $event.target.value)" />
    <input type="password" :value="password" @input="$emit('update:password', $event.target.value)" />
  </form>
</template>

<script>
export default {
  name: "TextField",
  props: {
    username: {
      type: String
    },
    password: {
      type: String
    }
  }
};
</script>

That's it. I hope this article was helpful and now you know how to use the v-model in Vue 3.


Comments

Anything interesting to share? Write a comment.