Table of contents [Show]
- Introduction
- What Does Emitting Events Mean in Vue.js?
- Step 1: Setting Up the Vue Environment
- Step 2: Creating Parent and Child Components
- Step 3: Understanding the emit Mechanism
- Step 4: Passing Data from Child to Parent
- Step 5: Multiple Events
- Step 6: Event Naming Best Practices
- Step 7: Handling Events with Arguments
- Step 8: Dynamic Events
- Step 9: Event Modifiers
- Step 10: Debugging Emitted Events
- Step 11: Comparing Props vs Emits
- Step 12: Advanced Example - Todo App
- Conclusion
Introduction
When I first started with Vue.js, I felt like a parent trying to understand my teenager’s cryptic text messages. The child component knew everything but refused to share it directly with me (the parent component). That’s when I discovered the magic of emitting events in Vue.js. Suddenly, communication was smooth, controlled, and predictable.
This article will walk you through the concept of child-to-parent communication using $emit in Vue.js, from basics to advanced techniques, with step-by-step code examples.
What Does Emitting Events Mean in Vue.js?
In Vue.js, components follow a unidirectional data flow: data usually goes from parent to child using props. But sometimes, the child component needs to send information back. Instead of directly modifying parent data, Vue uses events to keep things clean and decoupled.
Real-Life Analogy
Think of it like this: a child raises their hand (emits an event), and the parent decides how to respond (listens and acts). This separation keeps responsibilities clear.
Step 1: Setting Up the Vue Environment
Let’s start with a basic Vue 3 project using Vite. Run these commands in your terminal:
npm init vue@latest vue-event-demo
cd vue-event-demo
npm install
npm run devThis creates a Vue app ready for development.
Step 2: Creating Parent and Child Components
We’ll create two components: ParentComponent.vue and ChildComponent.vue.
Child Component
<template>
<button @click="notifyParent">Click Me</button>
</template>
<script setup>
import { defineEmits } from 'vue';
const emit = defineEmits(['childClicked']);
function notifyParent() {
emit('childClicked', 'The child says hello!');
}
</script>Parent Component
<template>
<div>
<h2>Parent Component</h2>
<ChildComponent @childClicked="handleChildEvent" />
<p>Message: {{ message }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
const message = ref('');
function handleChildEvent(payload) {
message.value = payload;
}
</script>In this simple example, the child emits childClicked, and the parent listens for it.
Step 3: Understanding the emit Mechanism
The emit function allows the child to send signals to the parent. Here’s the breakdown:
- defineEmits: Declares which events a component can emit.
- emit('eventName', data): Triggers the event with optional data.
- @eventName: The parent listens using Vue’s event binding.
Step 4: Passing Data from Child to Parent
Events are powerful because you can attach data. For instance, when a user fills a form in the child component, you can pass the form data to the parent.
Child Component with Input
<template>
<div>
<input v-model="username" placeholder="Enter your name" />
<button @click="submitForm">Submit</button>
</div>
</template>
<script setup>
import { ref } from 'vue';
import { defineEmits } from 'vue';
const username = ref('');
const emit = defineEmits(['formSubmitted']);
function submitForm() {
emit('formSubmitted', username.value);
}
</script>Parent Component
<template>
<div>
<h2>Form Example</h2>
<ChildComponent @formSubmitted="receiveFormData" />
<p>User entered: {{ user }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
const user = ref('');
function receiveFormData(data) {
user.value = data;
}
</script>Step 5: Multiple Events
A child component can emit multiple events. For example:
<script setup>
import { defineEmits } from 'vue';
const emit = defineEmits(['saved', 'deleted']);
function save() {
emit('saved', { status: 'success' });
}
function remove() {
emit('deleted', { status: 'removed' });
}
</script>Step 6: Event Naming Best Practices
- Use kebab-case for event names (e.g.,
user-logged-in). - Be descriptive but concise.
- Avoid generic names like
event.
Step 7: Handling Events with Arguments
You can pass multiple arguments by emitting an object:
emit('userUpdated', { id: 1, name: 'Alice', role: 'Admin' });Parent:
<ChildComponent @userUpdated="updateHandler" />
function updateHandler(user) {
console.log('Updated user:', user);
}Step 8: Dynamic Events
You can dynamically decide which event to emit:
function trigger(eventType) {
emit(eventType, 'Some payload');
}Step 9: Event Modifiers
Vue supports event modifiers when listening in the parent:
<ChildComponent @childClicked.stop="handleChildEvent" />This stops event propagation.
Step 10: Debugging Emitted Events
Use Vue Devtools to inspect events. Under the “Events” tab, you’ll see every event emitted with its payload. This makes debugging straightforward.
Step 11: Comparing Props vs Emits
Props pass data down; emits send events up. Here’s a comparison:
| Direction | Props | Emits |
|---|---|---|
| Data Flow | Parent ? Child | Child ? Parent |
| Use Case | Providing initial data, configurations | Communicating actions, results |
Step 12: Advanced Example - Todo App
Let’s build a mini todo app. The child handles adding tasks, and the parent manages the list.
Child Component
<template>
<div>
<input v-model="task" placeholder="New task" />
<button @click="addTask">Add</button>
</div>
</template>
<script setup>
import { ref } from 'vue';
import { defineEmits } from 'vue';
const task = ref('');
const emit = defineEmits(['taskAdded']);
function addTask() {
if (task.value.trim() !== '') {
emit('taskAdded', task.value);
task.value = '';
}
}
</script>Parent Component
<template>
<div>
<h2>Todo App</h2>
<ChildComponent @taskAdded="addNewTask" />
<ul>
<li v-for="(item, index) in tasks" :key="index">{{ item }}</li>
</ul>
</div>
</template>
<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
const tasks = ref([]);
function addNewTask(task) {
tasks.value.push(task);
}
</script>Conclusion
By now, you should feel confident about emitting events from child to parent in Vue.js. We’ve explored the basics of $emit, passing data, handling multiple events, using best practices, and building practical examples like forms and todo apps.
Next time you’re working on a Vue.js project, remember: props send data down, emits send events up. This simple rule will keep your components clean and your development experience smoother.
So go ahead—let your child components raise their hands proudly, and let the parent respond wisely.





