Emitting Events

Props only flow one direction, down from parent to child — so when a child needs to tell its parent something happened, it emits a custom event instead, and the parent listens for it the same way it'd listen for a native click.

Emitting a custom event from a child

this.$emit(eventName, payload) fires a named event that the parent can listen for with the same @ syntax used for native DOM events:

JS LikeButton component
app.component('like-button', {
  data() {
    return { liked: false }
  },
  methods: {
    toggleLike() {
      this.liked = !this.liked
      this.$emit('like-changed', this.liked)
    }
  },
  template: `<button @click="toggleLike">{{ liked ? 'Liked' : 'Like' }}</button>`
})
HTML parent template
<like-button @like-changed="handleLikeChanged"></like-button>
JS parent methods
methods: {
  handleLikeChanged(isLiked) {
    console.log('Like status is now:', isLiked)
  }
}
Console, after one click
Like status is now: true

The child never touches the parent's data directly — it just announces "something happened, here's the new value," and the parent decides what to do with that information. This keeps the child reusable: it works the same way no matter what parent uses it, or what that parent does in response.

Declaring emitted events

Just like props, it's good practice to declare which events a component can emit, using the emits option — this documents the component's public interface and lets Vue warn about typos:

JS being explicit
app.component('like-button', {
  emits: ['like-changed'],
  // ...rest unchanged
})
Props down, events up: this is the core communication pattern in Vue (and most component-based UI frameworks). A component's props are its inputs; its emitted events are its outputs. If you ever find yourself wanting a child to directly modify a parent's data, that's the signal to emit an event and let the parent make the change itself, rather than reaching across the boundary.