Vue’s new and improved prop.sync

In Vue 2.3, the .sync modifier, which was removed in the past, has been reintroduced in a new way.

This post is going to explore two approaches to passing props down to child components and passing up the updates. The first is the familiar v-model and it’s Vue 2.2 update, and the second will be with .sync.

v-model

The parent component binds speaks to the child with the v-model directive.

<template>
<doggie v-model="speaks" />
</template>
<script>
export default {
data: {
speaks: 'bark!'
}
}
</script>

Meanwhile the child declares a value prop which has the value of speaks.

It also emits an input event when the actual <input /> fires its own input event. The value passed to that event will update the parent’s speaks.

<template>
<input :value="value" @input="$emit('input', $event.target.value)" />
</template>
export default {
props: ['value'],
}

The child component using the prop value is just a default behavior, just like the name of the emit being input. Both can be overridden (if you’re using Vue 2.2+) by adding model to the child like this:

export default {  
props: ['sound'],
model: {
prop: 'sound',
event: 'updateSound'
},
}

Furthermore, now you can still declare thevalue prop for the child, except it won’t be tied to v-model anymore. Here’s the final working example.

.sync

Disclaimer: This works in Vue 2.3+

On obvious difference between v-model and .sync is the syntax. Here’s how the parent component could look.

<template>
<doggie :size.sync="size" />
</template>
<script>
export default {
data: {
size: 'little'
}
}
</script>

With .sync, the child doesn’t need a value prop. Instead it uses the same prop name you synced in the parent.

It also instead of emitting an input event to update the prop, you emit the conveniently named event update:prop-name. This is the main difference between the old .sync and the new one. Now we need to emit this update event to stay consistent with how we update parent component data like how we do with v-model.

This is how the child could look.

<template>
<input :value="size" @input="$emit('update:size', $event.target.value)" />
</template>
export default {
props: ['size'],
}

Another difference is that you can sync more than one prop to a component. Here’s the final working code.

Thank you for checking this post out. If there’s something you feel I’ve left out, feel free to share in the comments below.