Vue 3 Input Field Reactivity Between Parent-Child Components

Javascript Vue.js

Sometimes we need to move an input field that is bound to a reactive variable from a parent component to its own component for reusability purposes without losing its reactivity.

In the below parent component, the input field is bound to a variable name using ref() object.

You can get Up and Running With Vue JS 3 Project Using Vue CLI [2021] if you’ve not already.

Parent.vue

<template>
    Parent: {{name}}
    <input type="text" placeholder="Name" v-model="name"/>
</template>

<script>
import { ref } from "vue";
export default {
  setup() {
    const name = ref("");
    return { name };
  },
};
</script>

When you type anything in the name field, we can see the exact text appear above knowing that the two-way data binding is working as expected.

Most of the time, you would need to create a child component, which will end up having the input fields.

Create A Child Component

Let’s create a child component called InputField.vue.

InputField.vue

<template>
      <input type="text" placeholder="Name" v-model="name" />
</template>

Import A Child Component

<template>
   <InputField  />
</template>

<script>
...
import InputField from "@/components/InputField";
export default {
  components: {
    InputField,
  },
 ...
};
</script>

Sync Input Data To The Parent Component

Attach an @input event to the input field in the child component to emit user typed data to the parent.

InputField.vue (child component)

<input
  type="text"
  placeholder="Name"
  v-model="name"
  @input="$emit('update:modelValue', $event.target.value)"
/>

In the parent component, bind the name variable to the child component using v-model as we normally do.

Parent.vue

<InputField v-model="name" />

And this will work as expected.

So what about the v-model=”name” in the child component?

We can still use the v-model with a different name (just so we are not confused) to keep the reactivity in the child component as well.

InputField.vue (child component)

<template>
    Child: {{ input }}
      <input
        type="text"
        v-model="input"
        @input="$emit('update:modelValue', $event.target.value)"
      />
</template>

<script>
import { ref } from "vue";
export default {
  setup() {
    const input = ref("");
    return { input };
  },
};
</script>

At this stage, we can access the input value from the child component for making any inline type validation. At the same time, we can have access to the input data in the parent component for making CRUD operations, etc.

There you have it!