A modal is a type of user interface that displays content in a layer above the app. The key characteristic of a modal is that it disables the main content until the user explicitly interacts with the modal. Modals can be effective tools in UX design when used appropriately. In the Salesforce Lightning experience, modals are used for use cases like creating or editing a record, various types of messaging, and wizards. Developers often have requirements to use modals in their custom applications as well.

The Salesforce Lightning Design System (SLDS) provides a blueprint for developers needing to implement modals for their applications. However, maintaining a lot of boilerplate code has been a major pain point for developers building custom Lightning Web Components (LWCs) and wanting to utilize modals. With the Winter ’23 release, we now ship LightningModal (see docs), a base Lightning component that makes it simpler to incorporate modals into your components. LightningModal is based on the SLDS blueprint and follows guidelines for accessibility.

Using LightningModal in an application is covered extensively in the docs, and our LWC sample app, lwc-recipes, has a well-written example. In this blog post, we’ll focus specifically on modal events, which are tricky to understand. Specifically, with an example, we’ll dive deep into how to pass data from your Lightning web component to the modal component and vice versa. The aim is to help you understand how to work with the LightningModal component.

An example use case

To understand how to pass data from your Lightning Web Component to the modal component and vice versa, we’ll explore code snippets from an example LWC app, “Mascot Explorer.” I created this app to help us learn how to use modal events.

The Mascot Picker LWC component within the Mascot Explorer app lets you pick your favorite Salesforce Mascot. Codey is what I would pick, but I will leave it up to you to choose one!

You can grab the full source code for the app or watch the video below to see how the component works.

Component Composition

The Mascot Picker app consists of the following components.

  • A LWC component named “Mascot Picker” launches the modal component.
  • A LWC component named “Mascot Picker Modal” launched as a modal from the “Mascot Picker” LWC component. This component uses the LightningModal base component.
  • A visual picker LWC component named “Visual Picker” is contained within the “Mascot Picker Modal” LWC component (a child of the Mascot Picker Modal LWC component). The Visual Picker component has an input form element of the type radio to allow the selection of your favorite Mascot.

The diagram below can help you visualize how various components are composed.

Component composition of the Mascot Picker app

Creating the Mascot Picker Modal LWC component

mascotPickerModal is an LWC component launched as a modal from the Mascot Picker LWC component. It is built using the LightningModal base component. The mascotPickerModal LWC component is unique in how it is extended. Typically, when creating your component, the JavaScript module of the component extends the ES6 class LightningElement. When creating a modal component, the JavaScript module of the component extends the ES6 class LightningModal.

The code for the mascotPickerModal component is as below.

And here is the JavaScript module:

Code highlights

  • The mascotPickerModal component extends LightningModal as shown below.
  • You can define the modal header, body, and footer using out-of-box component markups as shown in the code snippets below.
  • The body of the modal in our example uses a custom LWC component, visualPicker. This component fires a select event to indicate mascot selection. The selection event is handled by the mascotPickerModal component.
  • When the Confirm button in the modal footer is clicked, the component dispatches a Select event. This is shown in the code snippets below. The select event is handled in the Mascot Picker LWC component covered in the next section.

Launching the Mascot Picker Modal LWC component as a modal from the Mascot Picker LWC component

The Mascot Picker Modal component we covered in the previous section is launched as a modal from the Mascot Picker LWC component. In our example, the mascotPicker component has a lightning-button to open the modal component.

The code snippet to launch the mascotPickerModal LWC component as modal is shown below.

The JavaScript snippet to launch the mascotPickerModal LWC component as modal from the Mascot Picker LWC component is shown below.

Code highlights

  • The mascotPickerModal LWC component is imported to the Mascot Picker LWC component using a simple import statement
  • To open the mascotPickerModal LWC component as modal, use the .open() method

NOTE – The LightningModal also supports the headless variant. You can leave out the lighnting-modal-header and lighnting-modal-footer. Make sure to add the ‘label’ attribute to the .open method for accessibility.

  • You can pass in the data from the Mascot Picker component to the mascotPickerModal component by using the @api properties declared in the mascotPickerModal component’s JavaScript module

The diagram below shows the flow of data between the Mascot Picker LWC component (the component that launches the modal) and the mascotPickerModal (launched as a modal) LWC component.

Flow of data between the Mascot Picker LWC component and the mascotPickerModal LWC component

  • You can listen for the events in the Mascot Picker component dispatched from the mascotPickerModal component. To do this, bind the events to the .open() method of the mascotPickerModal component’s class. This is shown in the code snippet below.

The diagram below shows how to dispatch and capture events between the Mascot Picker LWC component and the mascotPickerModal LWC component.

Flow of events between the Mascot Picker LWC component and the mascotPickerModal LWC component

NOTE – ‘oneventname’ on the left of the image and ‘eventname’ on the right is the key to naming events.

To summarize, there are two ways of moving data out of the LightningModal:

  1. By closing the Modal and passing the data in the close() method.
  2. Modal events are covered in the previous diagram.

Considerations

At the time of writing this blog post, we found an issue with the LightningModal component for those who have the Lightning Web Security (LWS) setting disabled in their orgs. The issue is that the events dispatched from the lightning-button in the LightningModal do not fire. The error encountered is usually shown when you debug via the Chrome developer console as: 'EventTarget': parameter 1 is not of type 'Event'.

We have a workaround for the above issue till you enable LWS setting for your org. Wrap the component within the modal that dispatches the event into its dedicated LWC component.

For our example app to work in orgs that have LWS disabled, I have created a dedicated LWC component buttonWrapper that dispatches the custom events that can be handled in the component launching the modal. We use this wrapper component instead of the standard lightning-button to get the modal events working.

The code for the Button Wrapper LWC component used as a child component in the mascotPickerModal LWC component is shown below.

The component markup:

The JavaScript module:

The modified component markup of the mascotPickermodal LWC is using the new buttonWrapper as a child component is shown below.

To see the complete working source code of the app with custom events for orgs with disabled Lightning Web Security, check out the source code in the branch, lws-disabled.

Conclusion

The LightningModal component also comes with built-in features, such as SLDS blueprint styles, accessibility, and support for styling hooks. Read more on this in the docs. A dedicated component for building modals means less boilerplate code and improved developer efficiency.

Further Resources

About the author

Mohith Shrivastava

Mohith Shrivastava is a Developer Advocate at Salesforce with a decade of experience building enterprise-scale products on the Salesforce Platform. He is presently focusing on the Salesforce Developer Tools, Flow, Apex, and Lightning Web Components at Salesforce. Mohith is currently among the lead contributors on Salesforce Stack Exchange, a developer forum where Salesforce Developers can ask questions and share knowledge. You can follow him via his Twitter @msrivastav13.

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

Add to Slack Subscribe to RSS