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.
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] });