Communicate Between Unrelated Components

To communicate across the subtrees in the DOM (and under some circumstances between different browser windows logged into the same org), use Lightning message service (LMS). LMS is a publish and subscribe service that facilitates communication between Lightning web components, Aura components, and Visualforce pages.  

Use LMS for communication between unrelated components unless you control both components and a common parent. LMS is powerful, effective, and easy to use, but don’t let that tempt you to use it when it’s not necessary. Firing DOM events is much more efficient. When you need to communicate between components with a parent that you can’t control, such as two App Builder slots, Lightning message service is the perfect choice.

LMS communication diagram showing a document object that contains several elements, including one element within a parent element. LMS channels are represented by unidirectional and bidirectional arrows between elements.

A third business unit wants in on the number manipulation project. They need the Prior Count and Count to be together in their own component so they can display them wherever they need to. Let’s start with creating the message channel so it’s ready for the components to use.

A component named remoteControl sends information to an unrelated component named counts.

Create a Lightning Message Channel

  1. In Visual Studio Code, in the default folder, create a folder named messageChannels.
  2. In the messageChannels folder, create a file named Count_Updated.messageChannel-meta.xml.
  3. In Count_Updated.messageChannel-meta.xml, paste this code:
    <?xml version="1.0" encoding="UTF-8" ?>
    <LightningMessageChannel xmlns="http://soap.sforce.com/2006/04/metadata">
        <masterLabel>CountUpdated</masterLabel>
        <isExposed>true</isExposed>
        <description>Message Channel to pass Count updates</description>
         <lightningMessageFields>
            <fieldName>operator</fieldName>
            <description>This is the operator type of the manipulation</description>
        </lightningMessageFields>
        <lightningMessageFields>
             <fieldName>constant</fieldName>
            <description>This is the number for the manipulation</description>
         </lightningMessageFields>
    </LightningMessageChannel>
  4. Save and deploy the file.

Create the Publisher Component

  1. Create a Lightning web component named remoteControl.
  2. Replace the contents of remoteControl.js with this code:
    import { LightningElement, wire } from 'lwc';
    import { publish, MessageContext } from 'lightning/messageService';
    import COUNT_UPDATED_CHANNEL from '@salesforce/messageChannel/Count_Updated__c';
    export default class RemoteControl extends LightningElement {
      @wire(MessageContext)
      messageContext;
      handleIncrement() {
        // this.counter++;
        const payload = { 
          operator: 'add',
          constant: 1
        };
        publish(this.messageContext, COUNT_UPDATED_CHANNEL, payload);
      }
      handleDecrement() {
        // this.counter--;
        const payload = { 
          operator: 'subtract',
          constant: 1
        };
        publish(this.messageContext, COUNT_UPDATED_CHANNEL, payload);
      }
      handleMultiply(event) {
        const factor = event.detail;
         // this.counter *= factor;
        const payload = { 
          operator: 'multiply',
          constant: factor
        };
        publish(this.messageContext, COUNT_UPDATED_CHANNEL, payload);
      }
    }
    We import publish and MessageContext from the Lightning message service. We also import the channel we just created (Count_Updated__c). The data payload is sent with the publish function.
  3. Save the file.
  4. Open remoteControl.html and add this code between the template tags:
      <lightning-card title="Remote Control" icon-name="action:change_record_type">
        <c-controls
          class="slds-show slds-is-relative"
          onadd={handleIncrement}
          onsubtract={handleDecrement}
          onmultiply={handleMultiply}>
        </c-controls>
      </lightning-card>
    Notice that we’re re-using the controls component.
  5. Save the file.
  6. Update remoteControl.js-meta.xml to make the remoteControl component available on Lightning app pages:
        <isExposed>true</isExposed>
        <targets>
            <target>lightning__AppPage</target>
        </targets>
  7. Save the file.

Create the Subscriber Component

  1. Create a Lightning web component named counts.
  2. Replace the contents of counts.js with this code:
    import { LightningElement, wire } from 'lwc';
    import { subscribe, MessageContext } from 'lightning/messageService';
    import COUNT_UPDATED_CHANNEL from '@salesforce/messageChannel/Count_Updated__c';
    export default class Counts extends LightningElement {
      subscription = null;
      priorCount = 0;
      counter = 0;
      @wire(MessageContext)
      messageContext;
      subscribeToMessageChannel() {
        this.subscription = subscribe(
          this.messageContext,
          COUNT_UPDATED_CHANNEL,
          (message) => this.handleMessage(message)
        );
      }
      handleMessage(message) {
        this.priorCount = this.counter;
        if(message.operator == 'add') {
          this.counter += message.constant;
        }else if(message.operator == 'subtract') {
          this.counter -= message.constant;
        } else {
          this.counter *= message.constant;
        }
      }
      connectedCallback() {
        this.subscribeToMessageChannel();
      }
    }
    @wire(MessageContext) ensures that unsubscribe runs during the component destruction lifecycle.
  3. Save the file.
  4. Open counts.html and add this code between the template tags:
      <lightning-card title="Counts" icon-name="action:change_record_type">
        <p class="slds-text-align_center slds-var-m-vertical_medium">
          Prior Count: <lightning-formatted-number value={priorCount}></lightning-formatted-number>
        </p>
        <p class="slds-text-align_center slds-var-m-vertical_medium">
          Count: <lightning-formatted-number value={counter}></lightning-formatted-number>
        </p>
      </lightning-card>
  5. Save the file.
  6. Update counts.js-meta.xml to make the counts component available in Lightning app pages:
        <isExposed>true</isExposed>
        <targets>
            <target>lightning__AppPage</target>
        </targets>
  7. Save the file.

Add the New Components to the Event Comms App

  1. Deploy the lwc folder and then refresh the Event Comms app page.
  2. Open the Event Comms page for editing.
  3. Drag the remoteControl component to the right region of the page.
  4. Drag the counts component to the right region, just under the remoteControl component.
  5. Click Save and then exit Lightning App Builder.

Verify communications

  1. Click the buttons in Remote Control to change the count in the counts component.

You can use Lightning message service to communicate with Aura components and Visualforce pages as well. It’s the cleanest way to keep different types of components in sync. 

Now you have a good working knowledge of how to communicate between Lightning web components. You worked through child-to-parent, parent-to-child, and unrelated component scenarios. Be sure to check out the resources to learn more about communicating with Lightning web components.

Resources