Multi level component communication event in Lightning web component

LWC

Communication between related LWC components using events is one of the interesting topic to explore with. This blog is sharing about event navigation from child to grand Child component. Lightning component have by default communication from bottom to Top. but if we want to communicate from Grand child => Child => Parent => Grand Parent.

We need to be aware of the Event Propagation – when to use bubbles and composed (cautiously). Salesforce LWC Documentation provides robust information around it. In short,

  • bubbles – passes the data bubbling up through the DOM.
  • composed – the data crosses the shadow boundary.

You might also want to know the best practices before implementing bubbling and composed as it might expose our data through the DOM even crossing the shadow boundary.

below code will help to understand

GrandChildComponent.html:-

<template>
    <lightning-card title="Grand Child Component">
      <div class="slds-box slds-var-m-around_large">
        This is <strong> Grand Child</strong> Component
        <div>
          <lightning-button label="Grand Child Button" onclick={handleGrandChildSubmit}></lightning-button>
        </div>
        <div><strong>Message Sent: </strong>{messageSend}</div>
        <div><strong>Message Received: </strong>{messageReceived}</div>
      </div>
      <br />
    </lightning-card>
  </template>

GrandChildComponent.js

import { api, LightningElement } from 'lwc';

export default class GrandChildComponent extends LightningElement {
    @api messageReceived;
    messageSend;

    handleGrandChildSubmit() {
        this.messageSend = "This is From Grand Child Component";
        this.dispatchEvent(
          new CustomEvent("grandchildcompevent", {
            detail: this.messageSend,
            bubbles: true,
            composed: true
          })
        );
      }

}

GrandChildComponent.js-meta.xml

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>55.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
      <target>lightning__RecordPage</target>
    </targets>
</LightningComponentBundle>

ChildComponent.html

<template>
    <lightning-card title="Child Component">
      <div class="slds-box slds-var-m-around_large">
        This is <strong>Child</strong> Component
        <div>
          <lightning-button label="Child Button" onclick={handleChildSubmit}></lightning-button>
        </div>
        <div><strong>Message Sent: </strong>{messageSend}</div>
        <div><strong>Message Received: </strong>{messageReceived}</div>
      </div>
      <br />
    </lightning-card>
  
    <!-- Grand Child Component -->
    <div>
      <c-grand-child-component ongrandchildcompevent={handlegrandChildEvent} message-received={messageSend}></c-grand-child-component>
    </div>
  </template>

ChildComponent.js

import { api, LightningElement } from 'lwc';

export default class ChildComponent extends LightningElement {
    @api messageReceived;
    messageSend;

    handleChildSubmit(){
        this.messageSend = "This is From Child Component";
        this.dispatchEvent(
          new CustomEvent("childcompevent", {
            detail: this.messageSend,
            bubbles: true,
            composed: true
          })
        );
    }
    handlegrandChildEvent(event) {
        this.messageReceived = event.detail;
      }

}

ChildComponent.js-meta.xml

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>55.0</apiVersion>
   <isExposed>true</isExposed>
    <targets>
       <target>lightning__RecordPage</target>
    </targets>
</LightningComponentBundle>

ParentComponent.html

<template>
    <lightning-card title="Parent Component">
      <div class="slds-box slds-var-m-around_large">
        This is <strong>Parent Componet</strong> Component
        <div>
          <lightning-button label="Parent Button" onclick={handleParentSubmit}></lightning-button>
        </div>
        <div><strong>Message Sent: </strong>{messageSend}</div>
        <div><strong>Message Received: </strong>{messageReceived}</div>
      </div>
      <br />
    </lightning-card>
  
    <!-- Child -->
    <div>
      <c-child-component onchildcompevent={handleChildEvent} ongrandchildcompevent={handlegrandChildEvent} message-received={messageSend}></c-child-component>
    </div>
  </template>

ParentComponent.js

import { api, LightningElement } from 'lwc';

export default class ParentComponent extends LightningElement {

    @api messageReceived;
    messageSend;

    handleParentSubmit(){
        this.messageSend = 'Message Received from Parent Componet ';
        this.dispatchEvent(
            new CustomEvent("parentcompevent", {
              detail: this.messageSend,
              bubbles: true,
              composed: true
            })
          );
    }

    handleChildEvent(event) {
        this.messageReceived = event.detail;
      }
    
      handlegrandChildEvent(event) {
        this.messageReceived = event.detail;
        alert(this.messageReceived);
      }
}

ParentComponent.js-meta.xml

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>55.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
       <target>lightning__RecordPage</target>
    </targets>
</LightningComponentBundle>

grandParentComponent.html

<template>
    <lightning-card title="Grand Parent Component">
      <div class="slds-box slds-var-m-around_large">
        This is <strong>Grand Parent Component</strong> Component
        <div>
          <lightning-button label="Grand Parent Button" onclick={handleGrandParentSubmit}></lightning-button>
        </div>
        <div><strong>Message Sent: </strong>{messageSend}</div>
        <div><strong>Message Received: </strong>{messageReceived}</div>
      </div>
      <br />
    </lightning-card>
  
    <!-- Parent -->
     <div>
        <c-parent-component onparentevent={handleParentEvent}
        onchildcompevent={handleChildEvent}
        ongrandchildcompevent={handlegrandChildEvent}
        message-received={messageSend}></c-parent-component>
      </div>
  </template>

grandParentComponent.js

import { LightningElement } from 'lwc';

export default class GrandParentComponent extends LightningElement {

    messageReceived;
    messageSend;
  
    handleGrandParentSubmit() {
      this.messageSend = "From Grand Parent Component";
    }
  
    handleParentEvent(event) {
      this.messageReceived = event.detail;
    }
  
    handleChildEvent(event) {
      this.messageReceived = event.detail;
    }
  
    handlegrandChildEvent(event) {
      this.messageReceived = event.detail;
    }
}

grandParentComponent.js-meta.xml

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>55.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
       <target>lightning__RecordPage</target>
    </targets>
</LightningComponentBundle>

Leave a Reply