Easily Add Confirmation Dialogs to your Lightning Components with lwcModal!

Overview
lwcModal
provides an easy way for LWC developers to add modals (aka pop-up dialogs) to components they’re building. It serves two related but distinct use cases:
- Customizable, composable modal. Pass any markup into the modal, including custom buttons. This part I
shamelessly stoletook inspiration from James Simone’s blog post and component and made a few tweaks. - Programmatic user confirmation. Embed user confirmation—that is, presenting the user with a message and the choice to confirm an action or cancel it—into your functions without modifying your markup. This is what really makes lwcModal worth talking about, IMO.
Features
Custom Modal
I highly recommend reading James’ blog post because mostly I’m just trying to replicate what he did. You can wrap lwcModal
around any custom markup you define. The modal is hidden by default. Select the component using this.template.querySelector()
, then call the component’s open()
function to display the modal and close()
to hide it again. This is commonly used for create/edit screens.
You can optionally set any of the following properties:
Name | Required | Default | Description | |
header | Header text of the modal. Default is none. | |||
cancelButtonLabel | Cancel | Label for the Cancel button. | ||
confirmButtonLabel | Label for the Confirm button. Unless a value is provided, the Confirm button is not displayed. | |||
confirmButtonVariant | brand | Variant for the Confirm button. Supported values are brand (default), neutral, outline-brand, destructive, text-destructive, success. | ||
validateOnConfirm | false | Before dispatching the Confirm event, run reportValidity() on all Lightning input elements that have been slotted in and only proceed if they all pass. |
The component dispatches the following custom events:
buttonclick
: fires when the user clicks any of the footer buttons (Confirm, Cancel, or a custom slotted button).confirm
: fires when the user clicks the Confirm button.cancel
: fires when the user clicks the Cancel button.
Note that the buttonclick
event is dispatched any time any of the buttons in the modal footer are clicked. When the Confirm or Cancel button are clicked, a second event is then also dispatched: confirm
or cancel
, respectively. As a developer you can mostly just use onconfirm
; onbuttonclick
is primarily designed for the confirmation functionality and oncancel
is rarely necessary (normally just having the modal close when the user clicks Cancel is all you want, and it does that on its own).
Programmatic Confirmation
A common use case for confirmation is when the user clicks a button that triggers an important action, such as deleting a record or submitting a form, to protect against the possibility of an accidental click or warn the user of the impact their action will have. Currently, there’s no native LWC way to capture this confirmation. Developers can use modals (either building their own or installing a custom component) to pop up the confirmation, but each individual confirmation requires modifying your markup and adding complexity to your code. lwcModal
allows you to add just one compact, generic “confirmation” component to your markup and programmatically invoke it from one or more of the event handlers in your component.
Below is a simplified example of programmatically requiring user confirmation for a given action.
lwcModalDemo.html
<template>
<lightning-button
label="Delete EVERYTHING"
icon-name="utility:delete"
onclick={handleDeleteClick}></lightning-button>
<c-lwc-modal
class="confirmation"
confirmation={confirmation}
onbuttonclick={handleModalButtonClick}></c-lwc-modal>
</template>
lwcModalDemo.js
import { LightningElement } from 'lwc';
import { getConfirmation, handleConfirmationButtonClick } from 'c/lwcModalUtil';
export default class LwcModal extends LightningElement {
@track confirmation;
deleteConfirmationDetails = {
text: 'Are you sure you want to delete everything?',
confirmButtonLabel: 'Delete',
confirmButtonVariant: 'destructive',
cancelButtonLabel: 'Never mind',
header: 'Confirm Delete'
};
handleDeleteClick(event) {
this.confirmation = getConfirmation(
this.deleteConfirmationDetails, // modal configurations
() => this.deleteEverything(), // callback function when user 'confirm' clicks confirm
// optional: () => this.handleCancel()
);
}
// We pass the event to the function imported from the utility class along with the confirmation object
handleModalButtonClick(event) {
handleConfirmationButtonClick(event, this.confirmation);
}
deleteEverything() {
// Delete everything... or whatever you want to happen when the user confirms
}
}
Our markup contains a standard issue Delete button with a standard issue onclick
event handler. Next is our lwcModal
component, which is hidden from view until it’s called upon by the controller. The modal has an event handler for a custom event called onbuttonclick
, which calls handleModalButtonClick
. The other important attribute is confirmation
, which represents the confirmation interaction, as we’ll see in the JS controller.


In our JS controller, we first import two functions from lwcModalUtil
.
getConfirmation()
will be used to generate a confirmation instancehandleConfirmationButtonClick()
is invoked when the user clicks either the confirm or cancel button in the modal
Then we declare our confirmation
object. Again, this object represents our confirmation interaction, by which I mean the process of presenting a message to the user, asking them to click either a Confirm or a Cancel button, and then acting on the user’s selection. As such, our confirmation
object consists of the following properties:
details
: (required) defines the look and feel of a modal, such as header and body text and button labels.onconfirm()
: (required) a callback function to be invoked when the user clicks the Confirm button.oncancel()
: (optional) a callback function to be invoked when the user clicks the Cancel button.
Next we define what we want our Delete confirmation modal to look like with deleteConfirmationDetails
. This details object supports the following properties:
Name | Required | Default | Description |
text | TRUE | Body text of the modal. This should explain to the user what you are asking them to confirm or cancel. | |
header | Header text of the modal. | ||
confirmButtonLabel | Confirm | Label for the “confirm” button. | |
confirmButtonVariant | brand | Variant for the “confirm” button. Supported values are brand (default), neutral, outline-brand, destructive, text-destructive, success. | |
cancelButtonLabel | Cancel | Label for the “cancel” button. |
Now it’s time to bring it all together. In handleDeleteClick()
, which is called anytime our demo Delete button is clicked, we set the value of our confirmation
object by calling getConfirmation
, which we imported from the utility class. It takes the following parameters:
Name | Required | Description |
details | TRUE | The configuration details for a confirmation modal. This value can either be a details object (see above), or a string value containing the modal body text; if you enter a string, all other details properties will use their default values. |
onconfirm | TRUE | Callback function to be executed when the user clicks the confirm button. |
oncancel | Callback function to be executed when the user clicks the cancel button. By default, the modal closes and no other actions are taken. |
Last but not least, we have handleModalButtonClick
, which is the event handler for the onbuttonclick
event on the lwcModal
component. That means that this handler gets invoked when the user clicks the Confirm or Cancel buttons. All we need to do here is call the handleConfirmationButtonClick
function from the utility file and pass along event
and our configuration
object as we’ve defined it. Since we already defined which actions the modal is supposed to take onconfirm
and oncancel
(if any), this function simply tells the component which of those outcomes to trigger.
Source Code
https://github.com/fromsteinsfdc/lwc-modal
Note that the repo also contains a component lwcModalTest
which serves as a more sophisticated live demo than our sample code above, and showcases 3 different use cases of lwcModal
. Once installed, it can be dropped onto any Lightning App or Home page.
Screenshots & Examples
In addition to the confirmation functionality, whose utility is hopefully clear by now, another common use for modals is editing data. This is used not only for custom components, but is a common interface throughout Salesforce, like when you click “Edit” on a record page:

A recent example was the “Button Builder” interface I built for the Flow Button Bar component’s Custom Property Editor. I needed a way to enable users to modify multiple properties for each button without taking up a ton of space in the main editor. The solution? Show just the buttons themselves in the main editor, but allow users to open an “edit” modal for any one button. Here’s a quick clip of what that looks like:

Here’s another, simpler example of an input modal:

They can also be useful for simply presenting information to the user, either to let them know what’s about to happen before some kind of transition, or as a form of advanced help-text, presenting supplemental information to the user, as in the following examples:

