LWC is based on Web Components which basically means everything will be broken down in to small reusable pieces called Web Components.

By now we know the fact that event bubbling is nothing but events propagating top the pyramid by checking if there are any Event Listeners associated with its immediate parent and invoking it.

LWC doesn’t have event capturing rather it has something called composed, which basically means the event will have the capability to cross the shadow dom boundary and data can be pushed or leaked into the other component.

When we have multiple components in hierarchy different combinations of event propagation might take place and below mentioned is the list of all of them.

  • bubbles: false && composed: false
  • bubbles: true && composed: false
    • event bubbling in the present component and containing component
    • event bubbling only in containing component
  • bubbles: true && composed: true
  • bubbles: false && composed: true

bubbles: false && composed: false

In this variant events will not bubble and also events will not cross the shadow dom boundary. This is considered as one of the simplest and straight forward form of events.

Here is how we work with this configuration.

Here is the output, we can only see 1 log messages when there are 3 Event Listeners in the current component and 3 Event Listeners in the parent component.

In the above example the event that we are looking at dispatching is senddata, so the name of the event listener is going to be onsenddata.  (line no. 13 in child.js)

You can notice that we have Event Listeners on all the <div> tags that are wrapping the lightning button*(in child.html)* and also the <div> tags wrapping the child component <c-child></c-child> (in parent.html).

When you click on the button you will only see one log message and that is going to be Am in child component.

Let's look at what happened behind the scenes. On click of the button we are trying to get the reference to the div using this.template.querySelector('.buttonDiv') (line 11, child.js) and we are dispatching the event.

The default configuration when we don't mention anything in event is bubbles: false and composed: false, meaning, though we have Event Listeners around the div (line 3 & 4 in child.html) to which we got reference to earlier the events are not going to bubble up.

Also, since composed is false, events will not propagate or leak to the parent component and Event Listeners in parent component will be not invoked though we have Event Listeners in parent component ( line no. 3, 4, 5 in parent.html).

bubbles: true && composed: false

This is the most tricky part when it comes to event propagation. Since bubbles: true events can bubble and if there are any <div> tags surrounding the button which are have Event Listeners they will get triggered.

Now events can bubble in the component that originates the events (child.html) or events can bubble in the containing component (parent.html).

Event Bubbling in the present component and containing component

In the below example, we have events listeners surrounding the button and in the containing component. Towards the end the event handlers in the current component and containing component gets invoked.

Notice that though there is one Event Listener on the shadow host <c-child></c-child> it doesn’t get invoked.

Here is the output, we can only see 6 log messages when there are 7 Event Listeners.

Event Bubbling only in containing component

In the below example, we have events listeners surrounding the button and in the containing component. Nonetheless only the event handlers in the containing component gets invoked.

Here is the output, we can only see 4 log messages when there are 7 Event Listeners.

bubbles: true && composed: true

In this configuration once the event is generated it will bubble up and also it will cross the shadow dom boundary. As a developer we need to use this only when it's super required. Things might go for a toss with this configuration if we are not cautious.

The button on which we are trying to click is wrapped by three <div> tags, they have Event Listeners attached to them and they will be invoked.

Likewise since composed: true the event propagates and leaks to the parent component crossing the boundary.

The parent component that’s hosting the child component has three <div> tags with Event Listeners surrounding child component and the Event Listeners on them also will be triggered.

Here is the output, we can only see 7 log messages when there are 7 Event Listeners.

bubbles: false && composed: true

This configuration is not possible in LWC. You can go completely easy on this.