skip to Main Content

I’ve created several components that communicate with each other using custom events.

The issue is that I’m having difficulties with event propagation. I have an App.vue component that instantiates a GeneriqueButton component, which in turn instantiates a BaseButton component. I’ve added an event listener on GeneriqueButton with the .stop modifier to prevent event propagation to App.vue, but the event still bubbles up to App.vue, I’ve message in my console.

I don’t understand why the event continues to propagate despite the use of the .stop modifier. I’ve verified that the event is emitted from BaseButton, but it’s still captured by App.vue.

Here’s the code for the three components:

App.vue :

<template>
  <GeneriqueButton @base-button="printConsole"/>
</template>

<script setup>
import GeneriqueButton from './GeneriqueButton.vue'
function printConsole(event) {
  console.log('App.vue : BaseButton clicked !', event)
}
</script>

GeneriqueButton.vue

<template>
  <BaseButton @base-button.stop="printConsole" />
</template>

<script setup>
import BaseButton from './BaseButton.vue'
function printConsole(event) {
  console.log('GeneriqueButton.vue : BaseButton clicked !', event)
}
</script>

BaseButton.vue

<template>
  <button type="button" @click="$emit('base-button', $event)">
    Click me
  </button>
</template>

I use console.log in App.vue and GeneriqueButton.vue, each click on button I have 2 logs in my console:

.

Do you have any idea what might be causing this event propagation issue? Do you have any suggestions on how to fix it?

Thank you in advance for your help.

2

Answers


  1. It looks weird, but it is actually not the custom event bubbling up, but the listener propagating down.

    Here is what happens:

    • Your App.vue sets an event listener on the GeneriqueButton button component
    • GeneriqueButton does not declare an event by that name, so the listener is added to fallthrough attributes (the component’s attr object)
    • Since GeneriqueButton has a single root element, attrs are passed on to the root node, including the listener
    • GeneriqueButton also adds another event listener on BaseButton for the same event
    • BaseButton emits the (undeclared) event and both listeners are called

    Note that .stop will stop event propagation on native events, you could use it on the @click on the button to stop the click event from bubbling. It does not work on custom events, which do not bubble at all.

    Here is what you can do to avoid the situation:

    • do not set the event handler on App.vue, unless you explicitly want it to be passed to the nested single root element
    • make GeneriqueButton a non-single root element
    • disable fallthrough attributes on GeneriqueButton, as suggested by @TazHinkle
    Login or Signup to reply.
  2. As per the documentation of Vue3.JS custom events not falls under default event bubbling like native events.

    Unlike native DOM events, component-emitted events do not bubble. You can only listen to the events emitted by a direct child component. If there is a need to communicate between sibling or deeply nested components, use an external event bus or a global state management solution.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search