Skip to main content

Communication between Lightning Web Components. How many can we use?

About Us
Published by JET BI
13 November 2023
1252

Introduction 

Communication between components is crucial to creating responsive and dynamic applications. There are different ways to communicate between Lightning Web Components (LWC), depending on the relationship between the components or event being communicated. For each method, we'll look at a really simple example, focusing on information that only applies to that specific method. By the end of this article, you will have a better understanding of how to communicate between LWC.
 

What are the ways to communicate between components in LWC?
 

There are 3 ways to communicate between components in LWC:

  • Parent-to-Child communication is used when the Parent component's HTML file includes a Child component and we need to pass data from the Parent component to the Child component or call a function in the Child component.
  • Child-to-Parent communication is used when we need to pass data from the Child component to the Parent component.
  • Communication between unrelated components is used to exchange data between components that don’t have a common parent component.
  1. Parent-to-Child communication

To enable Parent-to-Child communication, the child component must have a public property or function declared using the @api decorator.

Pass data to a Child property

child.js

import { LightningElement, api } from 'lwc';


export default class Child extends LightningElement {
  @api childVar;
}


child.html

<template>
</template>


parent.html

<template>
  <c-child child-var={parentVar}></c-child>
</template>


parent.js

import { LightningElement } from 'lwc';


export default class Parent extends LightningElement {
  parentVar = 'Hello!';
}

 

Call a Child function

To call a child function, it is necessary to take into account that this can only be done after the child's component has entered the DOM. So in this example I am using the renderedCallback method.

child.js

import { LightningElement, api } from 'lwc';


export default class Child extends LightningElement {
  @api
  childFunction() {
    return 'Hello!';
  }
}


child.html

<template>
</template>


parent.js

import { LightningElement } from 'lwc';


export default class Parent extends LightningElement {
  renderedCallback() {
    let childCmp = this.template.querySelector('c-child');
    let result = childCmp.childFunction();
  }
}


parent.html

<template>
<c-child></c-child>
</template>

 

          2. Child-to-Parent communication

The Child component cannot directly pass data to the Parent component using property, so this can be done by dispatching a custom event from the Child component, and the Parent component must listen for this event. 

Child-to-Parent

child.js

import { LightningElement } from 'lwc';


export default class Child extends LightningElement {
  renderedCallback() {
    this.childFunction();
  }


  childFunction() {
    this.dispatchEvent(new CustomEvent('childevent', {
      detail: {
        childVar: 'Hello!',
      }
    }));
  }
}


child.html

<template>
</template>

 

parent.js

import { LightningElement } from 'lwc';


export default class Parent extends LightningElement {
  parentFunction(event) {
    let result = event.detail.childVar;
  }
}


parent.html

<template>
  <c-child onchildevent={parentFunction}></c-child>
</template>

 

Child-to-Grandparent

When we have a chain of nested components, we often need to pass data from a child component to the grandparent component. So we need to configure Event Propagation using the bubbles property set to true in dispatchEvent on the intermediate components (in our case, it is the Parent component).

child.js

import { LightningElement } from 'lwc';


export default class Child extends LightningElement {
  renderedCallback() {
    this.childFunction();
  }


  childFunction() {
    this.dispatchEvent(new CustomEvent('childevent', {
      detail: {
        childVar: 'Hello!',
      }
    }));
  }
}


child.html

<template>
</template>


parent.js

import { LightningElement } from 'lwc';


export default class Parent extends LightningElement {
  parentFunction(event) {
    this.dispatchEvent(new CustomEvent('parentevent', {
      bubbles: true,
      detail: event.detail
    }));
  }
}


parent.html

<template>
  <c-child onchildevent={parentFunction}></c-child>
</template>

 

grandparent.js

import { LightningElement } from 'lwc';


export default class Grandparent extends LightningElement {
  grandparentFunction(event) {
    let result = event.detail.childVar;
  }
}


grandparent.html

<template>
  <c-parent onparentevent={grandparentFunction}></c-parent>
</template>

 

3. Communication between unrelated components

To communicate between unrelated components Lightning Message Service (LMS) should be used. LMS is a publish and subscribe (pub-sub) service.

First of all, create a Message Channel. To do this, create a messageChannels folder in your project in VSCode. In the folder, create MyMessageChannel.messageChannel-meta.xml file with the content below and deploy it to your org.

MyMessageChannel.messageChannel-meta.xml

<?xml version="1.0" encoding="UTF-8" ?>
<LightningMessageChannel xmlns="http://soap.sforce.com/2006/04/metadata">
  <masterLabel>MyMessageChannel</masterLabel>
  <isExposed>true</isExposed>
  <description>Sends messages to unrelated components</description>
  <lightningMessageFields>
    <fieldName>value</fieldName>
    <description>The value to send to a component</description>
  </lightningMessageFields>
</LightningMessageChannel>

 

Then create 2 unrelated components. The first has an input field and publishes value from the field via the Message Channel. The second subscribes to this Message Channel and displays the value.

component1.html

<template>
  <lightning-input onchange={sendMessage}></lightning-input>
</template>


component1.js

import { LightningElement, wire } from 'lwc';
import { publish, MessageContext } from 'lightning/messageService';
import MY_MESSAGE_CHANNEL from '@salesforce/messageChannel/MyMessageChannel__c';


export default class Component1 extends LightningElement {
  @wire(MessageContext)
  messageContext;


  sendMessage(event) {
    const payload = {
      value: event.target.value,
    };
    publish(this.messageContext, MY_MESSAGE_CHANNEL, payload);
  }
}


component2.html

<template>
  <p>{value}</p>
</template>

 

component2.js

import { LightningElement, wire } from 'lwc';
import { subscribe, MessageContext } from 'lightning/messageService';
import MY_MESSAGE_CHANNEL from '@salesforce/messageChannel/MyMessageChannel__c';


export default class Component1 extends LightningElement {
  value;
  subscription;


  @wire(MessageContext)
  messageContext;


  connectedCallback() {
    this.subscribeToMessageChannel();
  }


  subscribeToMessageChannel() {
    this.subscription = subscribe(
      this.messageContext,
      MY_MESSAGE_CHANNEL,
      (message) => this.handleMessage(message)
    );
  }


  handleMessage(message) {
    this.value = message.value;
  }
}

 

Conclusion

We've covered Parent-to-Child, Child-to-Parent and unrelated components communications. I hope the examples above have helped you gain a clearer understanding of how to communicate between Lightning Web Components.

If you need any help, don’t hesitate to contact us. Leave a request and we will help you!


Egor Glyakov
Salesforce Developer
image
Expertise
Question to the expert
image

We have available resources to start working on your project within 5 business days

1 UX Designer

image

1 Admin

image

2 QA engineers

image

1 Consultant

image
Related Articles
All articles
image
Is Salesforce Winning the Public Sector Race?
An analysis of Salesforce's rapid expansion into the U.S. public sector, tracing its path from cautious early government licensing deals in the 2010s through the launch of Government Cloud in 2012, its pivotal role in COVID-19 vaccine rollouts, and its 2025–2026 push into military and intelligence work via Agentforce and Missionforce. The piece covers major 2026 contracts — including a $5.6 billion Army deal, a $1.6 billion VA agreement, and Pentagon Impact Level 5 authorization — alongside real-world case studies like California's REAL ID processing and the UK's NHS back-office operations. It also examines the structural obstacles still facing Salesforce and other vendors in government tech: legacy IT systems decades old, outdated federal procurement rules, budget constraints, and organizational caution around AI adoption, plus the competitive pressure from Palantir, Microsoft, and Oracle in the race for public sector AI spending.
28 August 2026
image
Why Your Salesforce Flows Are Agentforce's Biggest Problem
This article argues that the most underestimated risk in Agentforce deployments isn't data quality — it's the automation layer: years of overlapping Flows, Process Builder processes, Apex triggers, and managed package logic that no one has reviewed end-to-end. It explains why AI agents inherit automation complexity without the tribal knowledge human admins carry, why technical debt only becomes visible after an agent hits it in production, and why a clean demo is no indicator of production readiness. The article closes with a concrete, tool-by-tool inventory approach using Flow Trigger Explorer, Salesforce Optimizer, Setup Audit Trail, Apex Debug Logs, Agent Builder, and Health Check — scoped to the specific processes the agent will actually use rather than the whole org.
23 July 2026
image
How to Wire Multiple Salesforce Projects in One Org Without Breaking Everything
This article maps the real integration patterns that emerge when multiple Salesforce projects — both managed packages and unpackaged code — share a single org. It covers four concrete patterns: attaching custom triggers to package-owned objects, calling global members exposed by managed packages, writing directly into another project's objects, and runtime-guarded reads of package data. It then addresses access control for authenticated and guest users, including the Master-Detail wall and the without sharing elevation pattern. The piece closes with eight concrete risks (compile-time dependencies that block uninstall, upgrade coupling, silent cascade failures, access invisible to admins) and six actionable recommendations for keeping cross-project coupling manageable.
08 July 2026