v-model changes in Vue 3

On custom components, v-model now passes a modelValue prop and listens to update:modelValue. The value prop and input event convention, the model option and the .sync modifier are gone. Native inputs are not affected.

Official guide: v-model, Vue 3 migration guide

Components using value and input

Vue 2
BaseInput.js
export default {
  props: ['value'],
  methods: {
    onInput(event) {
      this.$emit('input', event.target.value)
    },
  },
}
Vue 3
BaseInput.js
export default {
  props: ['modelValue'],
  emits: ['update:modelValue'],
  methods: {
    onInput(event) {
      this.$emit('update:modelValue', event.target.value)
    },
  },
}

Parents keep writing <base-input v-model="email" />.

Components using the model option

Vue 2
MyCheckbox.js
export default {
  model: { prop: 'checked', event: 'change' },
  props: ['checked'],
}
// parent: <my-checkbox v-model="agreed" />
Vue 3
MyCheckbox.js
export default {
  props: ['checked'],
  emits: ['update:checked'],
}
// parent: <my-checkbox v-model:checked="agreed" />

.sync becomes v-model with an argument

Vue 2
Editor.vue
<template>
  <text-document :title.sync="doc.title" />
</template>
Vue 3
Editor.vue
<template>
  <text-document v-model:title="doc.title" />
</template>

The child keeps emitting update:title, so this rewrite is safe, and npx vueleap --fix applies it for you. Components can now accept several v-model bindings, one per argument.

How vueleap detects it

vueleap reports components that declare a value prop and emit input, components with a model option (rule component-v-model, compat flag COMPONENT_V_MODEL) and every .sync modifier (rule sync-modifier, compat flag COMPILER_V_BIND_SYNC), which it can rewrite automatically.

Run it on your project:

Terminalbash
npx vueleap