LearnAI ToolsCareerPractice BuildsPlayContact
Lesson 1715 min read

Custom Events (emit)

Communicate from a child component back to its parent using defineEmits and the emit function.

Declaring and Emitting an Event

A component declares the custom events it can emit with defineEmits, then calls the returned emit function to actually fire one.

<!-- LikeButton.vue -->
<script setup>
const emit = defineEmits(['liked']);
function handleClick() {
emit('liked');
}
</script>
<template>
<button @click="handleClick">👍 Like</button>
</template>

Listening for the Event

A parent listens for a custom event using the same @ syntax as a native DOM event.

<script setup>
import LikeButton from './LikeButton.vue';
function handleLike() {
console.log('The post was liked!');
}
</script>
<template>
<LikeButton @liked="handleLike" />
</template>

Passing Data with an Event

Any extra arguments passed to emit() become arguments to the parent's handler.

<!-- Child -->
<script setup>
const emit = defineEmits(['update-quantity']);
function increase() {
emit('update-quantity', 1);
}
</script>
<!-- Parent -->
<script setup>
function handleQuantityChange(amount) {
quantity.value += amount;
}
</script>
<template>
<QuantityStepper @update-quantity="handleQuantityChange" />
</template>

v-model on a Custom Component

Combining a modelValue prop with an update:modelValue emit lets a custom component support v-model exactly like a native input — this is the standard pattern for building reusable form controls.

<!-- CustomInput.vue -->
<script setup>
defineProps(['modelValue']);
defineEmits(['update:modelValue']);
</script>
<template>
<input
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
/>
</template>
<!-- Parent -->
<script setup>
import { ref } from 'vue';
import CustomInput from './CustomInput.vue';
const search = ref('');
</script>
<template>
<CustomInput v-model="search" />
</template>

Common Beginner Mistakes

Forgetting to declare emitted events with defineEmits

Vue will still work without it, but you lose validation and the clear, self-documenting contract of what events a component can fire.

Trying to return a value directly from emit()

emit() has no return value — communication is one-directional (child to parent); to get a "response" back down, the parent updates a prop.

FAQs

Yes — defineEmits also accepts an object form with validator functions per event, similar to prop validation.

It's Vue's required naming convention for v-model to work on a custom component — v-model="x" expands to :model-value="x" plus @update:model-value.

Summary

Props flow down, and custom events flow up — together they form the complete communication channel between parent and child. Next, you'll learn slots, for passing markup (not just data) into a child.

Next Lesson →

Slots