There are three ways to communicate between Lightning Web Components: DOM events, Lightning Message Service (LMS), and Dynamic Interactions (DI). In this post, we’ll explore Dynamic Interactions that are Generally Available with the Spring ’22 release.

There are some key differences between DI and other communication techniques. For example, regular DOM events can only reach parent components, but DI and LMS allow you to reach sibling components within a page. DI also has the unique advantage of exposing the event data to the Lightning App Builder, so that an admin can declaratively configure interactions.

We’ll look at how you declare and fire a DI event with code, as well as how you receive it declaratively in the Lightning App Builder. We’ll illustrate these steps with a DI demo that showcases how you build a record selector component that communicates with a record form component.

Declare and fire a dynamic interaction event

In order to fire a DI event, you must declare it. This is done in the metadata descriptor (the .js-meta.xml file) of the Lightning Web Component that fires the event. This is an important difference with LMS that requires that you register a Message Channel metadata type.

A DI event is declared under the lightning__AppPage target configuration with an event tag.

Note: as of Spring ’22, DI events can only be fired by Lightning Web Components in Lightning app pages.

The event tag holds the event name that you use in JavaScript to fire the event. The event tag has a child schema tag that describes the event properties in JSON. In the example below, we declare a recordselected event with two string properties: recordId and objectApiName.

<targetConfig targets="lightning__AppPage">
  <event
      name="recordselected"
      label="Record Selected"
      description="This event fires when a record is selected."
  >
    <schema>
    {
      "type": "object",
      "properties": {
          "recordId": {
              "type": "string",
              "title": "Record ID",
              "description": "15 or 18-digit record ID"
          },
          "objectApiName": {
              "type": "string",
              "title": "Object API Name",
              "description": "An object API name (include '__c' for custom objects)"
          }
      }
    }
    </schema>
  </event>
</targetConfig>

Once you declare the event in the component metadata, you can dispatch it like a regular custom DOM event, but you must reuse the event and property names as defined in the component metadata.

this.dispatchEvent(
    new CustomEvent("recordselected", {
        detail: { objectApiName, recordId }
    })
);

At this point, you’re done with code, the rest of the process (receiving the event) is done declaratively in the Lightning App Builder.

Receive a dynamic interaction event

The configuration takes place in the Lightning App Builder on the component that fires the event (the record selector in our example).

You can configure multiple interactions upon receiving a DI event.

When selecting a component that declares DI events, you’ll notice an Interactions tab. This tab lists the different events that the component specifies and the existing interactions that may already be set up. From this view, you can add new interactions. You select the event and specify the type of interaction that you wish to configure (Update Properties in our case). At this point, you can get an overview of the event with its properties as specified in the component’s metadata.

Then, you select the target component for the interaction. Once you do this, you’ll have access to the Lightning App Builder properties that are exposed by the target component and you can update them with the data of the DI event.

In our example, our record form component exposes three properties to the Lightning App Builder: Object API Name, Record ID, and Number of Columns.

<targetConfig targets="lightning__AppPage">
  <property name="objectApiName" label="Object API Name" type="String"/>
  <property name="recordId" label="Record ID" type="String"/>
  <property name="columns" label="Number of Columns" type="Integer" min="1" default="1" required="true"/>
</targetConfig>

We use these properties to configure a lightning-record-form (see docs) that displays the selected record.

<lightning-record-form
  if:false={isEmptyState}
  object-api-name={objectApiName}
  record-id={recordId}
  layout-type="Full"
  mode="readonly"
  columns={columns}
  onerror={handleRecordFormError}
></lightning-record-form>

Using a Dynamic Interaction, we assign {!Event.objectApiName} to the Object API Name property and {!Event.recordId} to the Record ID property. This lets us pass the DI event data dynamically to the record form component, so that we display the details of the selected record.

Closing words

That’s a wrap — we’ve seen how you can declare and fire a DI event, how you can receive it, and how to trigger an interaction declaratively in the Lightning App Builder. We’ve covered some of the specificities of DI compared to other communication techniques, such as LMS. Here is a table that summarizes these differences and some resources that will help get you hands on with Dynamic Interactions.

Dynamic Interactions Lightning Messaging Service Custom DOM Events
Communicate between components within a page Only with sibling components, not child to parent Child to parent and sibling components Only from child to parent
Communicate between components in different tabs or in the utility bar No Yes No
Event registration In source component’s metadata descriptor Requires a message channel metadata type In source component’s code
Supported technology for event firing LWC LWC, Aura, or Visualforce LWC
Event handling Declaratively in App Builder Programmatic Programmatic
Receiving component is decoupled from the event definition Yes, any component can react to a DI event including standard ones No, received message channel must be imported/referenced in code Yes
Supported page types Lightning app page as of Spring ’22 Most Lightning page types and Experience Cloud pages All

Resources

About the author

Philippe Ozil is a Principal Developer Advocate at Salesforce where he focuses on the Salesforce Platform. He writes technical content and speaks frequently at conferences. He is a full stack developer and enjoys working on DevOps, robotics, and VR projects. Follow him on Twitter @PhilippeOzil or check his GitHub projects @pozil.

Get the latest Salesforce Developer blog posts and podcast episodes via Slack or RSS.

Add to Slack Subscribe to RSS