Sending Data from a Child Component to Its Parent in Vue 3
Component communication is a fundamental part of Vue 3 applications. Parents usually pass data down through props, while children send information upward by emitting events. For values that represent a two-way component model, Vue also provides the v-model component contract.
1. Why Child-to-Parent Communication Matters
Common examples include:
- A form field component informing its parent that a value changed.
- A list item notifying its parent that the user selected or removed it.
- A reusable control reporting an action such as submit, close, or confirm.
Keeping this communication explicit helps components remain reusable and easier to test.
2. Emit an Event from the Child
The standard approach is to declare and emit a custom event.
<!-- ChildComponent.vue -->
<template>
<button @click="sendData">Send Data to Parent</button>
</template>
<script setup>
const emit = defineEmits(['update']);
function sendData() {
emit('update', 'Data from child');
}
</script>The parent listens for that event:
<!-- ParentComponent.vue -->
<template>
<ChildComponent @update="handleUpdate" />
</template>
<script setup>
import ChildComponent from './ChildComponent.vue';
function handleUpdate(data) {
console.log('Received from child:', data);
}
</script>A descriptive event name such as form-submitted, item-selected, or remove often communicates intent better than a generic update event.
3. Use v-model for a Component Value
When the child represents an editable value, Vue’s v-model contract can be a better fit:
<!-- ChildComponent.vue -->
<template>
<input
:value="modelValue"
@input="emit('update:modelValue', $event.target.value)"
/>
</template>
<script setup>
defineProps({ modelValue: String });
const emit = defineEmits(['update:modelValue']);
</script><!-- ParentComponent.vue -->
<template>
<ChildComponent v-model="parentValue" />
</template>
<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
const parentValue = ref('');
</script>This avoids maintaining a duplicated local value in the child unless the component genuinely needs one.
4. Practical Example
For a form component, the child can emit a submit event containing validated form data. The parent can then decide whether to call an API, update a store, close a modal, or display an error. The child remains focused on its own UI responsibility instead of knowing what the parent will do next.
5. Best Practices
- Keep data flow explicit: props go down, events go up.
- Use descriptive event names and, in TypeScript projects, type event payloads.
- Use
v-modelwhen a child represents a value that the parent owns. - Avoid long chains of prop/event forwarding when shared state, provide/inject, or a store would better express the relationship.
- Keep components decoupled from parent implementation details.
Conclusion
In Vue 3, child components typically communicate upward with emitted events. For value-oriented components, v-model builds on the same event model with the conventional modelValue and update:modelValue interface. Choosing the clearest pattern keeps component boundaries predictable and maintainable.