Recipe 13.3
Are you sure you want to do that?
Creating a Confirmation Dialog Web Component
Compatibility Note: Dialog
This feature may not be supported on all browsers yet. Please check the latest compatibility data before using in a production application.
Browser support for DialogThis example creates a confirmation dialog wrapped in a web component (custom element).
It makes the flow of showing the modal and waiting for the result a little easier by using a
Promise
.
When the custom dialog’s showModal
method is called, it shows the underlying dialog and returns
a Promise
that will be resolved once the modal is either confirmed or cancelled. The value of
the Promise
will be a boolean - true
if the user confirmed, or false
if they canceled.
Demo
Code
JavaScript
const template = document.createElement('template');
template.innerHTML = `
<dialog id="confirm">
<h2>Confirm</h2>
<p><slot></slot></p>
<button type="button" class="btn btn-primary confirm-button">Confirm</button>
<button type="button" class="btn btn-secondary cancel-button">Cancel</button>
</dialog>
`;
class ConfirmDialog extends HTMLElement {
connectedCallback() {
const shadowRoot = this.attachShadow({ mode: 'open' });
shadowRoot.appendChild(template.content.cloneNode(true));
this.dialog = shadowRoot.querySelector('dialog');
shadowRoot.querySelector('.confirm-button')
.addEventListener('click', () => {
this.dialog.close('confirm');
});
shadowRoot.querySelector('.cancel-button')
.addEventListener('click', () => {
this.dialog.close('cancel');
});
this.dialog.addEventListener('cancel', () => {
this.dialog.returnValue = 'cancel';
});
}
showModal() {
this.dialog.showModal();
return new Promise(resolve => {
this.dialog.addEventListener('close', () => {
resolve(this.dialog.returnValue === 'confirm');
}, { once: true });
});
}
}
if (!customElements.get('confirm-dialog')) {
customElements.define('confirm-dialog', ConfirmDialog);
}
const confirmDialog = document.querySelector('#confirm');
document.querySelector('#show-confirm')
.addEventListener('click', async () => {
const confirmed = await confirmDialog.showModal();
if (confirmed) {
result.textContent = '✅ User confirmed.';
} else {
result.textContent = '❌ User canceled.';
}
});
HTML
<style>
confirm-dialog:not(:defined) {
display: none;
}
</style>
<confirm-dialog id="confirm">
Are you sure you want to do that?
</confirm-dialog>
<button id="show-confirm" class="btn btn-primary">Show Confirmation</button>
<div id="result"></div>