Create modalbox with pure JavaScript

We har going to create a modalbox with pure JavaScript in this tutorial. A modalbox is a dialog window that is shown on top of a page, it can be used to show information and/or to get input from a user.

This plugin depends on annytab.effects (Pure javascript effects) that we have written about in a previous blog post.

We are going to create a modalbox that can be used to show information, to get input from a user or to show a confirmation dialog. The purpose is to create a flexible modalbox that can be used in many different situations.

This plugin has been tested and is working with Google Chrome (75.0.3770.100), Mozilla Firefox (67.0.4), Microsoft Edge (42.17134.1.0) and Internet Explorer (11.829.17134.0), without any polyfill. If you want to support older browsers, check out our post describing how to transpile and polyfill JavaScript.

Modalbox

Styling (CSS)

The styling for this plugin includes CSS for the structure and for a standardized confirmation box. The contents of the modalbox can have customized styling.

/* Containers */
.annytab-modalbox-container {
    display: none;
    z-index: 100;
    position: fixed;
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: rgba(0, 0, 0, 0.7);
    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#99000000, endColorstr=#99000000);
    -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#99000000, endColorstr=#99000000)";
}
.annytab-modalbox-wrapper {
    display: block;
    position: absolute;
    background-color: #ffffff;
    max-width: 100%;
    box-sizing: border-box;
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    overflow:auto;
}
.annytab-modalbox-padding {
    display: block;
    padding: 20px;
    text-align: left;
}

/* Wrapper positions */
.annytab-modalbox-wrapper.top-left {
    border-radius: 0;
    top: 0;
    left: 0;
    margin: 10px 40px 10px 10px;
    max-height: calc(100% - 20px);
}
.annytab-modalbox-wrapper.top-center {
    border-radius: 8px;
    top: 0;
    left: calc(50% - 40px); /* adjust for margin */
    -ms-transform: translateX(-50%);
    transform: translateX(-50%);
    margin: 10px 40px 10px 40px;
    max-height: calc(100% - 20px);
}
.annytab-modalbox-wrapper.top-right {
    border-radius: 0;
    top: 0;
    right: 0;
    margin: 10px 40px 10px 10px;
    max-height: calc(100% - 20px);
}

.annytab-modalbox-wrapper.center-center {
    border-radius: 8px;
    top: calc(50% - 40px); /* adjust for margin */
    left: calc(50% - 40px); /* adjust for margin */
    -ms-transform: translate(-50%, -50%);
    transform: translate(-50%, -50%);
    margin: 40px;
    max-height: calc(100% - 80px);
}

.annytab-modalbox-wrapper.bottom-left {
    border-radius: 0;
    bottom: 0;
    left: 0;
    margin: 10px 40px 10px 10px;
    max-height: calc(100% - 20px);
}

.annytab-modalbox-wrapper.bottom-center {
    border-radius: 8px;
    bottom: 0;
    left: calc(50% - 40px); /* adjust for margin */
    -ms-transform: translateX(-50%);
    transform: translateX(-50%);
    margin: 10px 40px 10px 40px;
    max-height: calc(100% - 20px);
}

.annytab-modalbox-wrapper.bottom-right {
    border-radius: 0;
    bottom: 0;
    right: 0;
    margin: 10px 40px 10px 10px;
    max-height: calc(100% - 20px);
}

/* Close */
.annytab-modalbox-close {
    position: absolute;
    width: 24px;
    height: 24px;
    top: 8px;
    right: 8px;
    cursor: pointer;
    opacity: 0.6;
    filter: alpha(opacity=60);
}
.annytab-modalbox-close:hover {
    opacity: 1;
    filter: alpha(opacity=100);
}
.annytab-modalbox-close:before, .annytab-modalbox-close:after {
    position: absolute;
    right: 12px;
    content: ' ';
    height: 24px;
    width: 2px;
    background-color: #ffffff;
}
.annytab-modalbox-close:before {
    transform: rotate(45deg);
}
.annytab-modalbox-close:after {
    transform: rotate(-45deg);
}

/* Standard box */
.annytab-modalbox-content {
    display: block;
    position: relative;
    max-width: 600px;
    background-color: #ffffff;
    padding: 0;
    margin: 0;
}

.annytab-modalbox-content-title {
    font-size: 24px;
    line-height: 36px;
    font-weight: bold;
    color: #000000;
    margin-bottom: 5px;
}

.annytab-modalbox-content-message {
    font-size: 16px;
    line-height: 24px;
}

.annytab-modalbox-content-buttonpanel {
    display:block;
    bottom: 0;
    text-align: right;
    margin-top: 20px;
}

.annytab-modalbox-content-button-cancel {
    display: inline-block;
    min-width: 80px;
    padding: 0 20px 0 20px;
    margin: 0 0 0 10px;
    color: #ffffff;
    text-align: center;
    font-size: 16px;
    line-height: 28px;
    background-color: #d9534f;
    border: 1px solid #d43f3a;
    border-radius: 4px;
    cursor: pointer;
    box-shadow: inset 0 1px 0 rgba(255,255,255,0.2);
}

.annytab-modalbox-content-button-ok {
    display: inline-block;
    min-width: 80px;
    padding: 0 20px 0 20px;
    margin: 0 0 0 10px;
    color: #ffffff;
    text-align: center;
    font-size: 16px;
    line-height: 28px;
    background-color: #4CAF50;
    border: 1px solid #3B873D;
    border-radius: 4px;
    cursor: pointer;
    box-shadow: inset 0 1px 0 rgba(255,255,255,0.2);
}

.annytab-modalbox-content-button-cancel:hover {
    background-color: #F25C5C;
    border-color: #d9534f;
    text-decoration: none;
}

.annytab-modalbox-content-button-ok:hover {
    background-color: #59CC5D;
    border-color: #4CAF50;
    text-decoration: none;
}

JavaScript

This plugin have a constructor that takes options as a parameter. Click events is added for all links with a given selector. This plugin have a public open-method that can be used to create a modalbox and a public close-method that can be used to close a modalbox.

var annytab = annytab || {};
annytab.modalbox = (function () {

    'use_strict';

    // Constructor
    function modalbox(opts)
    {
        // Set default values for parameters
        opts = opts || {};

        // Set options
        this.options = { selector: '.annytab-modalbox-popup', position: 'center-center', fade_duration: 1000, close_click_outside: false };
        for (var option in this.options) {
            if (opts.hasOwnProperty(option) === true) {
                this.options[option] = opts[option];
            }
        }

        // Set variables
        resetVariables(this);
        
        // Get all links that should have a modalbox
        var links = document.querySelectorAll(this.options.selector);

        // Add events
        addLinkEvents(this, links);

    } // End of the constructor

    // Reset variables to default values
    function resetVariables(mb)
    {
        mb.container = null;
        mb.wrapper = null;
        mb.close_button = null;
        mb.cancel_button = null;
        mb.ok_button = null;

    } // End of the resetVariables method

    // Add link events
    function addLinkEvents(mb, links)
    {
        // Loop links
        for (var i = 0; i < links.length; i++)
        {
            // Add a click event
            window.onload = links[i].addEventListener('click', function (event)
            {
                // Prevent default click behaviour
                event.preventDefault();

                // Open modalbox
                openWithHtml(mb, document.querySelector(this.getAttribute('href')).innerHTML, mb.options.position);

            }, false);
        }

    } // End of the addEvents method

    // Add container events
    function addContainerEvents(mb, callback, parameters)
    {
        // Add a close event for close button
        window.onload = mb.close_button.addEventListener('click', function (event)
        {
            // Prevent default click behaviour
            event.preventDefault();

            // Close the container
            mb.close();

        }, false);

        // Add a close event for click outside wrapper
        if (mb.options.close_click_outside === true)
        {
            window.onload = mb.container.addEventListener('click', function (event) {

                // Prevent default click behaviour
                event.preventDefault();

                // Close the modalbox
                if (event.target.contains(mb.wrapper) === true)
                {
                    mb.close();
                }

            }, false);
        }

        // Add a cancel click event
        if (mb.cancel_button !== null)
        {
            window.onload = mb.cancel_button.addEventListener('click', function (event) {

                // Prevent default click behaviour
                event.preventDefault();

                // Disable buttons
                mb.cancel_button.setAttribute('disabled', true);
                mb.ok_button.setAttribute('disabled', true);

                // Close the modalbox
                mb.close();

            }, false);
        }

        // Add a ok click event
        if (mb.ok_button !== null && callback !== null)
        {
            window.onload = mb.ok_button.addEventListener('click', function (event) {

                // Prevent default click behaviour
                event.preventDefault();

                // Disable buttons
                mb.ok_button.setAttribute('disabled', true);
                mb.cancel_button.setAttribute('disabled', true);

                // Call the callback function
                callback(parameters);

            }, false);
        }

    } // End of the addContainerEvents method

    // Open a modalbox with html
    function openWithHtml(mb, html, position, callback, parameters)
    {
        // Add a modalbox
        mb.container = document.createElement('div');
        mb.container.setAttribute('class', 'annytab-modalbox-container');
        mb.container.insertAdjacentHTML('beforeend',
            '<div class="annytab-modalbox-wrapper ' + position + '">'
            + '<div class="annytab-modalbox-padding">'
            + html
            + '</div></div>'
            + '<div class="annytab-modalbox-close"></div >');
        document.body.appendChild(mb.container);

        // Get references
        mb.wrapper = mb.container.querySelector('.annytab-modalbox-wrapper');
        mb.close_button = mb.container.querySelector('.annytab-modalbox-close');
        mb.cancel_button = mb.container.querySelector('.annytab-modalbox-content-button-cancel');
        mb.ok_button = mb.container.querySelector('.annytab-modalbox-content-button-ok');

        // Fade in the container
        annytab.effects.fadeIn(mb.container, mb.options.fade_duration, 'block');

        // Add container events
        addContainerEvents(mb, callback, parameters);

    } // End of the openWithHtml method

    // Open a modalbox
    modalbox.prototype.open = function (input)
    {
        // Get input
        var data = { html: null, position: this.options.position, title: 'Title', message: 'Message', ok_text: 'Ok', cancel_text: 'Cancel', callback: null, parameters: [] };
        for (var option in data) {
            if (input.hasOwnProperty(option) === true) {
                data[option] = input[option];
            }
        }

        // Check if we should create a customized modalbox or a standardized
        if (data.html !== null)
        {
            // Open a modalbox
            openWithHtml(this, data.html, data.position, data.callback, data.parameters);
        }
        else
        {
            var html = '<div class="annytab-modalbox-content">'
                + '<div class="annytab-modalbox-content-title">' + data.title + '</div>'
                + '<div class="annytab-modalbox-content-message">' + data.message + '</div>'
                + '<div class="annytab-modalbox-content-buttonpanel">'
                + '<input type="button" class="annytab-modalbox-content-button-ok" value="' + data.ok_text + '" />'
                + '<input type="button" class="annytab-modalbox-content-button-cancel" value="' + data.cancel_text + '" />'
                + '</div></div>';

            // Open a modalbox
            openWithHtml(this, html, data.position, data.callback, data.parameters);
        }

    }; // End of the open method

    // Close a modalbox
    modalbox.prototype.close = function ()
    {
        // Get a reference to the container
        var box = this.container;

        // Fade out the container
        annytab.effects.fadeOut(box, this.options.fade_duration);

        // Remove the container
        setTimeout(function ()
        {
            document.body.removeChild(box);

        }, this.options.fade_duration);
        
        // Reset variables (GC)
        resetVariables(this);

    }; // End of the close method

    // Return this object
    return modalbox;

})();

How to use this plugin with links

One way to use this plugin is to add links and hidden containers with contents. The href attribute in the link points to the container that should have it’s contents included in the modalbox.

@*Link*@
<a href="#modalbox-test" class="annytab-modalbox-popup">Open Modalbox</a>

@*Container*@
<div id="modalbox-test" style="display:none;">
    <div class="annytab-messagebox-container">
        <div class="annytab-messagebox-header">Delete files</div>
        <div class="annytab-messagebox-text">
            Are you sure that you want to delete files? They will be deleted permanently.
        </div>
        <div class="annytab-messagebox-button-panel">
            <input type="button" class="annytab-messagebox-button btn-green btn-disablable" value="Ok" onclick="disableButtons(); sayHello(['Bill', 'USA', 100]); enableButtons();" />
            <input type="button" class="annytab-messagebox-button btn-red btn-disablable" value="Cancel" onclick="disableButtons(); modalbox.close(); enableButtons(); " />
        </div>
    </div>
</div>
<script src="/js/annytab-shared/annytab.effects.js"></script>
<script src="/js/annytab-shared/annytab.modalbox.js"></script>
<script>

    // Modalbox
    var modalbox = new annytab.modalbox({ selector: '.annytab-modalbox-popup', position: 'center-center', fade_duration: 1000, close_click_outside: true });

    // Say hello to a person
    function sayHello(parameters)
    {
        // Log the message
        console.log('Hello ' + parameters[0] + ' from ' + parameters[1] + ', you got ' + parameters[2] + ' points!');

        // Close the modalbox
        modalbox.close();

    } // End of the sayHello method

    // Disable buttons
    function disableButtons()
    {
        var buttons = document.getElementsByClassName('btn-disablable');
        for (var i = 0; i < buttons.length; i++)
        {
            buttons[i].setAttribute('disabled', true);
        }

    } // End of the disableButtons method

    // Enable buttons
    function enableButtons()
    {
        var buttons = document.getElementsByClassName('btn-disablable');
        for (var i = 0; i < buttons.length; i++)
        {
            setTimeout(function (button) { button.removeAttribute('disabled'); }, 1000, buttons[i]);
        }

    } // End of the enableButtons method

</script>

How to use this plugin from script

You can also use this plugin by inserting contents directly from javascript. Some examples of this is shown below. Click events will be added if you insert button classes that is used by the plugin.

// Modalbox
var modalbox = new annytab.modalbox({ selector: '.annytab-modalbox-popup', position: 'center-center', fade_duration: 1000, close_click_outside: true });

// Open modalbox with html
modalbox.open({
    html: '<div class="annytab-messagebox-container">'
        + '<div class="annytab-messagebox-header">' + 'Do you need help?' + '</div>'
        + '<div class="annytab-messagebox-text">' + 'I can help you with any problem, just answer yes or no.' + '</div>'
        + '<div class="annytab-messagebox-button-panel">'
        + '<input type="button" class="annytab-messagebox-button btn-green btn-disablable" onclick="disableButtons(); sayHello([\'Donald\', \'Germany\', 33]); enableButtons();" value="Yes" />'
        + '<input type="button" class="annytab-messagebox-button btn-red btn-disablable" onclick="disableButtons(); modalbox.close(); enableButtons();" value="No" />'
        + '</div></div>', position: 'top-left'
});

// Open modalbox with html
modalbox.open({
    html: '<div class="annytab-modalbox-content">'
        + '<div class="annytab-modalbox-content-title">' + 'Do you need help?' + '</div>'
        + '<div class="annytab-modalbox-content-message">' + 'I can help you with any problem, just answer yes or no.' + '</div>'
        + '<div class="annytab-modalbox-content-buttonpanel">'
        + '<input type="button" class="annytab-modalbox-content-button-ok" value="Yes" />'
        + '<input type="button" class="annytab-modalbox-content-button-cancel" value="No" />'
        + '</div></div>', position: 'top-center', callback: sayHello, parameters: ['Marcus', 'France', 120]
});

// Open modalbox with html
modalbox.open({
    html: '<div style="display: block;max-width: 1024px;background-color: #ffffff;height: 100vh;">'
        + 'TEST fsdafadsf af asdfsdafsadf sadfsa dfsadfsadfsadfsadfsad fsadf sadfsadf sdfasdf dsafd saf dasdfsadff fd as fasdffdasd ff dasd ffdasfd f dasdf f d'
        + '</div>', position: 'bottom-right' });

// Open standard modalbox
modalbox.open({ position: 'center-center', title: 'Title', message: 'Message', ok_text: 'Ok', cancel_text: 'Cancel', callback: sayHello, parameters: ['Peter', 'Russia', 50] });

Leave a Reply

Your email address will not be published. Required fields are marked *