It’s been a good three years since I last wrote something, but anyways here we are.

Passing Props in Vue 3 is a one-way operation going from Child to Parent. This is quite normal for frameworks like Vue, and it’s also normal that you use an emit event to send a value from child to parent. Vue 3 uses v-model in order to simplify this whole process.

In this Example we use:

  • Vue 3 (I code in Composition API but you can easily convert this to Options API)
  • Vuetify 3 Framework (optional)


TLDR - Just show me the code

Parent Component (shows counter):

<template>
  <p>Parent counter: {{ state.counter }}</p>
  <br>
  <Child v-model="state.counter"></Child>
</template>

<script setup>
import Child from './Child.vue';
import { reactive } from 'vue';

const state = reactive({
  counter: 0
})
</script>

Child Component (shows and update counter):

<template>
    <!-- 
        We also show the counter on the child component to demonstrate that the counter
        on the parent and child components are in sync
     -->
    child counter: {{ props.modelValue }}
    <br>

    <!-- We emit a value to the parent component to increment/decrement the parent counter -->
    <v-btn @click.stop="e => $emit('update:modelValue', props.modelValue + 1)">+</v-btn>
    <v-btn @click.stop="e => $emit('update:modelValue', props.modelValue - 1)">-</v-btn>
</template>

<script setup>
// Outputs
defineEmits(['update:modelValue'])

// Inputs
const props = defineProps(['modelValue'])
</script>

It should look something like this:
v-model example 1


Understanding How Props are Passed to Child and updated values are emitted to Parent Components

In Vue, to pass values to from parent to child, we use v-bind e.g.

<Child v-bind:msg="some_value"/>

or short hand,

<Child :msg="some_value" />

Then we would emit an updated value from the Child Component to update the value in the Parent Component e.g.

<Child :msg="some_value" @update_msg="e => update_msg(e)" />

Here you can see that we use v-bind to pass "some_value" to the msg prop. Then, the Child component emits an event called “update_msg” to which we assign our updater function to.

We can simplify this process of passing a prop and updating using emit using v-model

realistically all v-model does in the previous example, is:

// With v-bind and a custom update function
<Child :msg="some_value" @update_msg="e => update_msg(e)" />

// With v-model
<Child v-model="some_value" />

IMPORTANT: In order to achieve this you need to do 2 things:

  1. Name the Child Component’s prop "modelValue" (If your child component accepts multiple props, you only need to name the prop that you will later update to this)
  2. Name the emit that is responsible for emitting the update value back to the parent, "update:modelValue".

Keep Reading, Examples Below

diagram 1

Code example of this is above in the TLDR section


Example 2 - Creating a custom Component to wrap around a Vuetify Component(s) and passing props and emits throught

In this example we have a Page called <FormPage> where we print a list of fruits. We then have a Child component in the Page called <CustomList> which takes in the list of fruits as a prop and allows you to select which fruits to activate via checkbox.

diagram 2

FormPage Component (Parent Component):

<template>
    Pick a fruit
    <br>
    list_items (Parent):
    <pre>{{ state.list_items }}</pre>
    <CustomList v-model="state.list_items"></CustomList>
</template>

<script setup>
import CustomList from './CustomList.vue';
import { reactive } from 'vue';
const state = reactive({
    list_items: []
})
</script>

CustomList Component (Child Component):

<template>
    <p>Checklist (Child)</p>
    <br>
    <!-- 
        we use v-bind:model-value because we are getting our model value from props 
        which is read-only. We then use the @update:model-value to emit the updated
        value from the v-checkbox
     -->
    <v-checkbox v-for="item in list_items" density="compact" :value="item" :label="item" :model-value="props.modelValue"
        @update:model-value="$event => $emit('update:modelValue', $event)"></v-checkbox>
</template>

<script setup>
const list_items = ["banana", "apple", "orange"]
// Inputs
const props = defineProps(['modelValue'])
// Outputs
defineEmits(['update:modelValue'])
</script>

It should look like this:

example 2