Tiny confirmation modal dialog in Vanilla JavaScript

on in JavaScript DOM
Last modified on

Thin UI Modal Dialog using Vanilla JavaScript
Thin UI Modal Dialog using Vanilla JavaScript

A new addition to my Thin UI library, a much-needed modal dialog (popup dialog), this script is tiny, and it works with anything you can throw at it. It’s written in Vanilla JavaScript with no dependencies.

One of my ongoing project needed several confirmations on several pages. As these actions might be delayed, I required something to work asynchronously. This script adds a custom Confirm popup dialog with Promise support to your website application.

The modal returns a Promise with the selected option: true if the user accepted, false if the user clicked cancel, and null if the user closed the modal window.

The modal constructor takes four parameters: the title, the content, and the button labels (“Accept” or “Cancel”).

See the example on the Thin UI page or a live CodePen below:

See the Pen RJS (alpha) by Ciprian (@ciprian) on CodePen.

For reference only, here is the JavaScript code. It is pretty self-explanatory.

'use strict';

/**
 * Class representing a simple modal dialog.
 */
class SimpleModal {
    /**
     * Create a SimpleModal instance.
     * @param {string} modalTitle - The title of the modal.
     * @param {string} modalText - The text content of the modal.
     * @param {string} acceptText - The text for the accept button.
     * @param {string} cancelText - The text for the cancel button.
     */
    constructor(modalTitle, modalText, acceptText, cancelText) {
        this.modalTitle = modalTitle || 'Hello world!';
        this.modalText = modalText || 'Are you sure you want to do this?';
        this.acceptText = acceptText || 'Yes';
        this.cancelText = cancelText || 'No';

        this.parent = document.body;

        this.modal = undefined;
        this.acceptButton = undefined;
        this.cancelButton = undefined;
        this.closeButton = undefined;

        this._createModal();
    }

    /**
     * Displays the modal and resolves a Promise based on user action.
     * @returns {Promise<boolean|null>} A Promise that resolves with true if the accept button is clicked, 
     * false if the cancel button is clicked, or null if the modal is closed.
     */
    question() {
        return new Promise((resolve, reject) => {
            if (!this.modal || !this.acceptButton || !this.cancelButton || !this.closeButton) {
                reject('There was a problem creating the modal window!');
                return;
            }
            this.acceptButton.focus();

            this.acceptButton.addEventListener('click', () => {
                resolve(true);
                this._destroyModal();
            });

            this.cancelButton.addEventListener('click', () => {
                resolve(false);
                this._destroyModal();
            });

            this.closeButton.addEventListener('click', () => {
                resolve(null);
                this._destroyModal();
            })
        })
    }

    /**
     * Creates the modal elements and appends them to the DOM.
     * @private
     */
    _createModal() {
        // Background dialog
        this.modal = document.createElement('dialog');
        this.modal.classList.add('thin-ui-modal-dialog');
        this.modal.show();

        // Message window
        const window = document.createElement('div');
        window.classList.add('thin-ui-modal-window');
        this.modal.appendChild(window);

        // Title
        const title = document.createElement('div');
        title.classList.add('thin-ui-modal-title');
        window.appendChild(title);

        // Title text
        const titleText = document.createElement('div');
        titleText.textContent = this.modalTitle;
        title.appendChild(titleText);

        // Close
        this.closeButton = document.createElement('button');
        this.closeButton.type = 'button';
        this.closeButton.innerHTML = '&times;';
        this.closeButton.classList.add('thin-ui-modal-close');
        title.appendChild(this.closeButton);

        // Main text
        const text = document.createElement('div');
        text.classList.add('thin-ui-modal-text');
        text.textContent = this.modalText;
        window.appendChild(text);

        // Accept and cancel button group
        const buttonGroup = document.createElement('div');
        buttonGroup.classList.add('thin-ui-modal-button-group');
        window.appendChild(buttonGroup);

        // Cancel button
        this.cancelButton = document.createElement('button');
        this.cancelButton.type = 'button';
        this.cancelButton.classList.add('thin-ui-button');
        this.cancelButton.classList.add('thin-ui-button-secondary');
        this.cancelButton.classList.add('thin-ui-button-regular');
        this.cancelButton.textContent = this.cancelText;
        buttonGroup.appendChild(this.cancelButton);

        // Accept button
        this.acceptButton = document.createElement('button');
        this.acceptButton.type = 'button';
        this.acceptButton.classList.add('thin-ui-button');
        this.acceptButton.classList.add('thin-ui-button-primary');
        this.acceptButton.classList.add('thin-ui-button-regular');
        this.acceptButton.textContent = this.acceptText;
        buttonGroup.appendChild(this.acceptButton);

        // Let's rock
        this.parent.appendChild(this.modal);
    }

    /**
     * Removes the modal from the DOM.
     * @private
     */
    _destroyModal() {
        this.parent.removeChild(this.modal);
        delete this;
    }
}

Related posts