On custom components v-model prop and event default names are changed.
- prop: value -> modelValue
- event: input -> update:modelValue
Vue 2
<ChildComponent v-model="pageTitle" /> <!-- would be shorthand for: --> <ChildComponent :value="pageTitle" @input="pageTitle = $event" />
Vue 3
<ChildComponent v-model="pageTitle" />
<!-- would be shorthand for: -->
<ChildComponent
:modelValue="pageTitle"
@update:modelValue="pageTitle = $event"
/>
Vue 2
// ChildComponent.vue
export default {
model: {
prop: 'title',
event: 'change'
},
props: {
// this allows using the `value` prop for a different purpose
value: String,
// use `title` as the prop which take the place of `value`
title: {
type: String,
default: 'Default title'
}
}
}
<ChildComponent v-model="pageTitle" />
<!-- would be shorthand for: -->
<ChildComponent :title="pageTitle" @change="pageTitle = $event" />
Vue 3
<ChildComponent v-model:title="pageTitle" />
<!-- would be shorthand for: -->
<ChildComponent
:title="pageTitle"
@update:title="pageTitle = $event"
/>
v-bind.sync and component model option are removed and replaced with an argument on v-model.
Vue 2
// ChildComponent.vue
this.$emit('update:title', newValue)
<!-- ParentComponent.vue -->
<ChildComponent :title.sync="pageTitle" />
<!-- would be shorthand for: -->
<ChildComponent :title="pageTitle" @update:title="pageTitle = $event" />
Vue 3
<ChildComponent v-model:title="pageTitle" v-model:content="pageContent" />
<!-- would be shorthand for: -->
<ChildComponent
:title="pageTitle"
@update:title="pageTitle = $event"
:content="pageContent"
@update:content="pageContent = $event"
/>
Keys are no longer necessary on v-if, v-else, v-else-if branches, since Vue now automatically generates unique keys. If provided, then each branch must use a unique key.
Vue 2
<div v-if="condition" key="a">Yes</div> <div v-else key="a">No</div>
Vue 3
<div v-if="condition">Yes</div> <div v-else>No</div> <!-- or --> <div v-if="condition" key="a">Yes</div> <div v-else key="b">No</div>
<template v-for> key should be placed on the <template> tag (rather than on its children).
Vue 2
<template v-for="item in list">
<div :key="'heading-' + item.id">...</div>
<span :key="'content-' + item.id">...</span>
</template>
Vue 3
<template v-for="item in list" :key="item.id">
<div>...</div>
<span>...</span>
</template>
If used on the same element, v-if will have higher precedence than v-for.
Vue 2
<li v-for="todo in todos" v=if="!todo.isComplete">
{{ todo.name }}
</li>
Vue 3
<template v-for="todo in todos">
<li v-if="!todo.isComplete">
{{ todo.name }}
</li>
</template>
Order of bindings for v-bind now affects the rendering result.
Vue 2
<!-- template -->
<div id="red" v-bind="{ id: 'blue' }"></div>
<!-- result -->
<div id="red"></div>
<!-- template -->
<div v-bind="{ id: 'blue' }" id="red"></div>
<!-- result -->
<div id="red"></div>
Vue 3
<!-- template -->
<div id="red" v-bind="{ id: 'blue' }"></div>
<!-- result -->
<div id="blue"></div>
<!-- template -->
<div v-bind="{ id: 'blue' }" id="red"></div>
<!-- result -->
<div id="red"></div>
The native modifier for v-on has been removed.
Vue 2
<ChildComponent
v-on:close="handleComponentEvent"
v-on:click.native="handleNativeClickEvent"
/>
Vue 3
// ChildComponent.vue
export default {
emits: ['close']
}
<!-- ParentComponent.vue -->
<ChildComponent
v-on:close="handleComponentEvent"
v-on:click="handleNativeClickEvent"
/>