ℹ️ This article deals with inter-component communication patterns for Aura components and will only be valuable for developers creating or maintaining custom UI using that framework.
Refer to this blog post for a Lightning Web Components version.
If you’re comfortable with how a Lightning Component works and want to build production-grade applications for use in your org or to sell in AppExchange, this article is a must read. Understanding how a singular component works is important, but understanding how they work together is essential for building an effective application.
In LCF, inter-component communication is supported in several well-defined ways. One can only use the following developer-defined interfaces to specify what can be exchanged:
- Attributes or Methods to pass data down the component hierarchy
- Lightning Events to pass data up and around in the component hierarchy
Passing data down the component hierarchy
Attributes are the most commonly used element to pass data down the component hierarchy as they are simple to use. In order to pass data down from a parent component to its child, simply use the following code:
In this example, the parent component value of
parentAttribute is transferred to the
childAttribute of the child component via the
This is perfect if you just want to display the data in a child component. What about if you also want to execute some logic when the attribute’s value changes?
Consider the following updated definition of
With the addition of a change handler, the child component can now trigger the
onChildAttributeChange controller function automatically when the value of
childAttribute changes. This allows us to implement some custom logic such as:
We now have established a top-down communication chain between the parent and the child component. This can be summarized in these few steps:
parentAttributevalue is transferred to
childComponent’s change handler triggers the
This approach works great for processing an attribute. What about multiple attribute changes? If you want to change two or more attributes and then trigger some logic, this method becomes unwieldy. You can either combine the attributes into a larger object (not always practical) or write a complex synchronization algorithm (please don’t). Instead, I recommend methods for multiple attribute changes.
Based on frequent exchanges with the developer community, I have gathered that methods tend to be overlooked in favor of attributes. However, I have found methods to be quite flexible, as they allow users to create and expose component APIs.
Let’s look at an example involving two components communicating with a method. Here we have a child component that exposes a
myMethod method with two parameters (
myMethod is hooked to an
executeMyMethod function in the component’s controller:
This function retrieves the arguments (
param2) passed to
myMethod and outputs them in the console. Note that the
arguments key used in
event.getParam is a constant.
Let’s now look at the parent component. It has two attributes (
parentAttribute2), a reference to the child component, and a button.
When clicked, the button calls a
onCallChildMethod function in the component’s controller. This function retrieves the value of the two attributes and retrieves the child component by using its
aura:id. It then calls a
myMethod method on the child component and passes the two attribute values as parameters.
If we now step back and look at the big picture, here’s what happens:
- When the parent component button is clicked, the
onCallChildMethodcontroller function of
onCallChildMethodretrieves a reference to
executeMyMethodcontroller function of
This “method” approach is quite powerful as users can pass data to a child component and perform some operations once this is done. Users can also create distinct methods involving the same arguments but triggering different functions. Finally, developers get the benefit of clarity by exposing named methods that—hopefully—reflect their intended behavior.
Achieving all of this is not possible by just passing attributes from parent to child components.
Passing data up and around the Lightning component hierarchy
The way to pass data up and around in the Lightning component hierarchy is to use events. There are two types of events that users can employ for that purpose: application events and component events.
There are some minor syntax differences between these two types of events, but we do not discuss them in this article for the sake of brevity. Instead, we focus on their propagation mechanisms, which in turn dictates their use cases.
Application events are broadcast to all Lightning components that are registered as listeners for that specific event.
If we look at the example described in the schema on the right, here’s what happens:
- A component fires an application event.
- All other components can handle the event provided that they have registered the appropriate event handler.
All event handlers are triggered simultaneously. There is no way to cancel an application event once fired.
Application events are great for supporting business logic events as they are quite flexible: They do not impose a particular architecture. This is ideal when building components that are exposed in the Lightning App Builder. However, bear in mind that this flexibility comes at the expense of performance in certain use cases due to the event broadcast.
For example, it can be expensive to use an application event for a fine-grained component such as a button to notify other components that it is clicked. Your event will be sent to all of the components. They have to identify the source of the event then, verify if they handle it. Typically all components except one are registered to handle the event. Conversely, if you use an application event for a coarse-grained event in the App Builder that two other components may listen to, there is no performance impact.
Component events are “clones” of standard DOM events (mouse clicks, key press, and so on). Just like their DOM counterparts, they propagate up in the component hierarchy via a bubbling mechanism and can be stopped en route to the application root component.
Here is an example of such a behavior:
- Component E fires a component event.
- Event bubbles to E’s direct parent: component D.
- Component D can handle the event or not and optionally prevent its propagation by capturing it.
- If Component D did not capture the event, it propagates to A (this applies even if D did not handle the event).
- Component B and C do not handle the event, as they are not in the ancestry line of E.
The advantage of component events is that you know their maximum scope in advance (all parent components) and you have some degree of control over it (you can capture the event along the way).
Advanced event architecture
As a rule, consider using a component event before employing an application event. These are more common and usually have little effect on performance. However, when facing a blocking use case or an overly complex architecture, think about going for an application event.
Consider using a component event for handling low-level UI interactions such as selections and form validation. You can then combine these with application events that handle “business” events. This integrates into a larger architecture via a central “dispatcher” component such as this:
In this article we covered Lightning inter-component communication options. You learned about passing data down the component hierarchy with attributes and methods. You also had an overview of the different event types with their use cases and limitations. You are now ready to build a larger Lightning project with a robust architecture that you can quickly deploy to production. If you have any questions, reach out to our community’s Stack Exchange.
Here are some working code samples covering the inter-component communication patterns presented in this post: