We are going to create a toast notifications plugin with pure JavaScript in this tutorial. A toast notification is a small message that is shown over other contents.
This notification plugin is able to show different messages. Notifications can be shown during a limited time, this is visualized by a progress bar. A notification that gets focus will restart it’s self-destruction process. A notification can be closed and all notifications can be removed by calling the clear method.
This plugin depends on annytab.effects and Font Awesome, these dependencies can easily be replaced by you if you want to use other icons and/or another library for effects.
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), without any polyfill. It works in Internet Explorer (11.829.17134.0) with a polyfill for CustomEvent. If you want to support older browsers, check out our post on transpilation and polyfilling of JavaScript.
JavaScript
This plugin does not have a constructor, it is static and can be used by calling the public methods: setOptions, show and clear. Notifications is created in a container and the container is removed when the last message is removed.
var annytab = annytab || {};
annytab.notifier = (function () {
'use_strict';
// Variables
var options = { duration: 10000, position: 'top-center', fade_duration: 1000 };
var container = null;
// Update options
function updateOptions(opts)
{
// Set default values for parameters
opts = opts || {};
// Update options
for (var option in options)
{
if (opts.hasOwnProperty(option) === true)
{
options[option] = opts[option];
}
}
// Return options
return options;
} // End of the updateOptions method
// Create a box
function create(type, message)
{
// Make sure that a container exists
if (container === null)
{
container = document.createElement('div');
container.setAttribute('class', 'annytab-notifier-container annytab-notifier-' + options.position);
document.body.appendChild(container);
}
// Set icon (Font Awesome)
var icon = '<i class="fas fa-exclamation fa-fw"></i>';
if (type === 'success') { icon = '<i class="fas fa-check-circle fa-fw"></i>'; }
else if (type === 'warning') { icon = '<i class="fas fa-exclamation-triangle fa-fw"></i>'; }
else if (type === 'info') { icon = '<i class="fas fa-info-circle fa-fw"></i>'; }
// Create a box
var box = document.createElement('div');
box.setAttribute('class', 'annytab-notifier-box annytab-notifier-' + type);
box.insertAdjacentHTML('beforeend',
'<div class="annytab-notifier-padding">'
+ '<div class="annytab-notifier-icon">' + icon + '</div>'
+ '<div class="annytab-notifier-message">'
+ message
+ '</div>'
+ '<div class="annytab-notifier-progress"></div>'
+ '<div class="annytab-notifier-close"></div >');
+ '</div>';
container.appendChild(box);
// Fade in the message box
annytab.effects.fadeIn(box, options.fade_duration, 'block');
// Add events
addBoxEvents(box);
// Return the box
return box;
} // End of the create method
// Add box events
function addBoxEvents(box)
{
// Variables
var close_button = box.querySelector('.annytab-notifier-close');
var progress = box.querySelector('.annytab-notifier-progress');
var progress_interval = null;
var close_timeout = null;
// Add a close event
window.onload = close_button.addEventListener('click', function (event) {
// Prevent default click behaviour
event.preventDefault();
// Close the box
close(box);
}, false);
// Check if the box should self destruct
if (options.duration > 0)
{
// Add self destruction event
window.onload = box.addEventListener('mouseleave', function (event) {
// Prevent default click behaviour
event.preventDefault();
// Check if the box is closing
if (annytab.effects.isVisible(close_button) === false) {
return;
}
// Display the progress bar
progress.style.display = 'block';
// Calculate the amount to decrease each interval
var width = 100;
var decrease = width / options.duration * 10;
// Set an interval to show progress
progress_interval = window.setInterval(function () {
width -= decrease;
progress.style.width = width + '%';
}, 10);
// Self destruct after some time
close_timeout = window.setTimeout(function () {
// Clear timeout and interval
clearTimeout(close_timeout);
clearInterval(progress_interval);
// Close the box
close(box);
}, options.duration);
}, false);
// On focus
window.onload = box.addEventListener('mouseenter', function (event) {
// Prevent default click behaviour
event.preventDefault();
// Check if the box is closing
if (annytab.effects.isVisible(close_button) === false)
{
return;
}
// Clear timeout and interval
clearTimeout(close_timeout);
clearInterval(progress_interval);
// Reset progress bar
progress.style.display = 'none';
progress.style.width = '100%';
}, false);
// Trigger a mouse leave event
box.dispatchEvent(new Event('mouseleave'));
}
} // End of the addBoxEvents method
// Close a box
function close(box)
{
// Get the close button
var close_button = box.querySelector('.annytab-notifier-close');
// Check if the box is closing
if (annytab.effects.isVisible(close_button) === false) {
return;
}
// Hide the close button
close_button.style.display = 'none';
// Fade out the box
annytab.effects.fadeOut(box, options.fade_duration);
// Wait for the fade effect to finish
setTimeout(function ()
{
// Remove the box
container.removeChild(box);
// Check if we should remove the container
if (container.querySelector('.annytab-notifier-box') === null) {
document.body.removeChild(container);
container = null;
}
}, options.fade_duration);
} // End of the close method
// Remove a container
function removeContainer()
{
// Make sure that the container exists
if (container !== null)
{
// Get all boxes in the container
var boxes = container.querySelectorAll('.annytab-notifier-box');
// Loop boxes
for (var i = 0; i < boxes.length; i++) {
// Close the box
close(boxes[i]);
}
}
} // End of the removeContainer method
// Public methods
return {
setOptions: function (opts) {
return updateOptions(opts);
},
show: function (type, message)
{
return create(type, message);
},
clear: function ()
{
removeContainer();
}
};
})();
Styling (CSS)
The container for notifications can be set at various positions on the screen, the center-center position might look a little blurry. The close button is created entirely in CSS and icons comes from Font Awesome.
/* Containers */
.annytab-notifier-container {
display: block;
z-index: 200;
position: fixed;
max-width: calc(100% - 10px); /* adjust for margin */
max-height: 100%;
overflow: auto;
}
/* General styles */
.annytab-notifier-box {
display: none;
position: relative;
margin: 5px;
width: 500px;
max-width: calc(100% - 10px); /* adjust for margin */
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.annytab-notifier-padding {
display: block;
padding: 15px 15px 15px 65px;
text-align: left;
}
.annytab-notifier-icon {
display: inline-block;
position: absolute;
font-size: 28px; /* 32px is actual height */
top: calc(50% - 16px);
left: 15px;
margin: auto;
}
.annytab-notifier-message {
font-size: 16px;
line-height: 24px;
}
.annytab-notifier-progress {
display: none;
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: 4px;
background-color: #d9d9d9;
}
/* Box positions */
.annytab-notifier-top-left {
top: 5px;
left: 5px;
}
.annytab-notifier-top-center {
top: 5px;
left: 50%;
-ms-transform: translateX(-50%);
transform: translateX(-50%);
}
.annytab-notifier-top-right {
top: 5px;
right: 5px;
}
.annytab-notifier-center-center {
top: 50%;
left: 50%;
-ms-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}
.annytab-notifier-bottom-left {
bottom: 5px;
left: 5px;
}
.annytab-notifier-bottom-center {
bottom: 5px;
left: 50%;
-ms-transform: translateX(-50%);
transform: translateX(-50%);
}
.annytab-notifier-bottom-right {
bottom: 5px;
right: 5px;
}
/* Message types */
.annytab-notifier-success {
background-color: #ffffff;
border: 4px solid #51A351;
color: #51A351;
}
.annytab-notifier-error {
background-color: #ffffff;
border: 4px solid #BD362F;
color: #BD362F;
}
.annytab-notifier-info {
background-color: #ffffff;
border: 4px solid #2F96B4;
color: #2F96B4;
}
.annytab-notifier-warning {
background-color: #ffffff;
border: 4px solid #CC7606;
color: #CC7606;
}
/* Close button */
.annytab-notifier-close
{
position: absolute;
width: 12px;
height: 12px;
top: 2px;
right: 2px;
cursor: pointer;
}
.annytab-notifier-close:before, .annytab-notifier-close:after {
position: absolute;
right: 5px;
content: ' ';
height: 12px;
width: 2px;
background-color: #000000;
}
.annytab-notifier-close:before {
transform: rotate(45deg);
}
.annytab-notifier-close:after {
transform: rotate(-45deg);
}
How to use this plugin
You can set options before you start to call methods in the plugin, default values will be used if you don’t set any options. Set the duration to a value less than 1 if you do not want notifications to be shown during a limited time, notifications have to be closed or cleared in that case.
<!--<script src="https://polyfill.io/v3/polyfill.min.js?features=CustomEvent"></script>-->
<link href="/css/annytab.notifier.css" rel="stylesheet" />
<script src="/js/font-awesome/v5.3.1/all.min.js"></script>
<script src="/js/annytab-shared/annytab.effects.js"></script>
<script src="/js/annytab-shared/annytab.notifier.js"></script>
<script>
// Set options
// Positions: top-left, top-center, top-right, center-center, bottom-left, bottom-center, bottom-right
annytab.notifier.setOptions({ duration: 10000, position: 'top-right', fade_duration: 1000 });
// Show success
annytab.notifier.show('success', 'Success, everything was perfect!');
// Show error
annytab.notifier.show('error', 'Something is wrong, it can be that or that.');
// Show information
annytab.notifier.show('info', 'I just want to inform you that it is going to rain today.');
// Show warning
annytab.notifier.show('warning', 'Warning for Internet Explorer, the worst browser that exists.');
</script>