@api properties. To talk up (Child → Parent), fire a CustomEvent. To talk to strangers (components anywhere else on the page), use the Lightning Message Service (LMS), which acts like a page-wide radio channel.
A user clicks "Add to Cart" on a product tile (Child). The tile fires a
CustomEvent('addtocart') upwards. The main product grid (Parent) catches that event, updates its internal state, and passes the new cart count down to the cart badge (another Child) via an @api property. Meanwhile, a mini-cart widget living totally separately in the page header listens to a Lightning Message Service (LMS) channel to know the cart was updated.
๐ก The 4 Directions of Communication
To keep components decoupled and reusable, you must strictly follow these unidirectional data flow patterns:
- Parent to Child (Down): The parent passes data down by setting public
@apiproperties on the child, or by calling a public@apimethod on the child element. - Child to Parent (Up): The child dispatches a standard JavaScript
CustomEvent. The parent listens for it using anon-handler in its HTML template. - Sibling to Sibling (Across): Siblings never talk directly! Child A fires an event up to the shared Parent. The Parent catches it, updates its state, and passes the new data down to Child B via
@api. The Parent acts as the traffic junction. - Unrelated Components (Anywhere): For components that do not share a parent (different page regions, utility bars, or even crossing between LWC, Aura, and Visualforce), use the Lightning Message Service (LMS).
@api). Actions flow UP via events (CustomEvent). Strangers talk over the radio (LMS).
๐งญ 360 Card — Component Communication
๐ Gain: You avoid "spaghetti state." By enforcing unidirectional data flow, you always know exactly where a piece of data lives and how it changes.
๐ฐ Price: The shared parent becomes the single source of truth (and the traffic junction) for sibling communication, which can bloat the parent component if not managed cleanly.
๐ Limits:
CustomEvent properties bubbles and composed default to false. A composed event pierces the shadow boundary and can be heard anywhere—it is powerful but leaky. ๐ฎ The Future: The choices you make here dictate whether legacy Aura or Visualforce components can participate. LMS is the only bridge that spans all three frameworks simultaneously.
๐ Core Q&A & Scenarios
@api. The parent acts as the traffic junction.
Detailed breakdown:
- Child A dispatches the event:
this.dispatchEvent(new CustomEvent('selectionchange', { detail: { id } })). It does not need bubbling, because the parent listens directly on the child's tag. - The parent handles the event, stores
selectedIdin its own state, and passes it down to Child B via an@apiproperty. - Child B reacts via a setter or a getter on that property.
- ๐จ Red Flag: Reaching for LMS to communicate between two direct siblings is a classic sign of over-engineering. LMS is strictly for components that do not share a convenient ancestor.
๐ป Code Example: Sibling Communication
// 1. childA.js fires the event upward
this.dispatchEvent(new CustomEvent('selectionchange', { detail: { id: this.value } }));
<!-- 2. parent.html listens and passes data down -->
<c-child-a onselectionchange={handleSelection}></c-child-a>
<c-child-b selected-id={selectedId}></c-child-b>
// 3. parent.js reads the payload and updates state
handleSelection(evt) {
this.selectedId = evt.detail.id;
}
bubbles and composed on a CustomEvent. When do you need them and what is the risk?A: By default, both are false, meaning the event is only heard by the element directly wrapping the dispatcher. This is the safest, recommended contract.
bubbles: truelets the event travel up the DOM tree, but it stops at the shadow boundary.composed: truelets the event pierce through the shadow boundary and escape into the enclosing DOM.- The Risk: A bubbling, composed event leaks into DOM you do not own. Unintended listeners might catch it, creating invisible, impossible-to-debug coupling. Use it as an absolute last resort.
A: You must use the Lightning Message Service (LMS). Define a message channel in your metadata. The utility bar publishes the event. The subscribers on the record page must subscribe using APPLICATION_SCOPE. (Because the utility bar lives outside the active page region, the default active-area scope would miss it). Always remember to unsubscribe in the disconnectedCallback! LMS is the only supported bridge across LWC, Aura, and Visualforce.
A: The backend publishes a Platform Event (or CDC). The LWC subscribes using the empApi module. While waiting for the event to arrive, show a truthful pending state (e.g., "Payment Processing"). For slow synchronous Apex callouts, use the Continuation pattern to park the request and free up the worker thread, showing a spinner until the response arrives.