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.
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 extendsLightningModal
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 themascotPickerModal
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
andlighnting-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 themascotPickerModal
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.
- 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 themascotPickerModal
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.
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:
- By closing the Modal and passing the data in the
close()
method. - 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
LightningModal
— component reference- SLDS Modal Blue Print
- LWC Recipes sample app — sample app with bite-sized recipes for learning LWC
About the author
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.