Alert notifications are very common on websites, for example, when we want to give a message to the user, it is very useful. This message can be of any kind, for example, successful registration of a banking operation or a warning for a failed banking operation, The user can be sure that this message will disappear after a while and leaving the message on the page will not cause him any annoyance because some users are very disgusted with the messages remaining on the site page.


HTML
<!-- this script got from www.devanswer.com -->
<link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css'> <link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css'> <div data-jc="toast" data-jc-config='timeout:6;format:dd\.MM\.yyyy hh\:mm;animate:fade;'></div> <div class='container'> <div class='row'> <div class='col-md-10 center-block' style='float:none;'> <div class="panel panel-default" style='margin: 20px 0; padding:10px;'> <h4>Several Toast Notify with Time Bar</h4> <div class='row'> <div class='col-md-8'> <div class="panel panel-default" style='margin: 20px 0; padding:10px;'> Toast type events:<br> <button data-bind="null__click:example" data-type='success' class='btn btn-default btn-sm'>Success</button> <button data-bind="null__click:example" data-type='warning' class='btn btn-default btn-sm'>Warning</button> <button data-bind="null__click:example" data-type='error' class='btn btn-default btn-sm'>Error</button> <button data-bind="null__click:example" data-type='info' class='btn btn-default btn-sm'>Info</button> <button data-bind="null__click:example" data-type='no' class='btn btn-default btn-sm'>No Type</button> <hr> Toast with date view:<br> <button data-bind="null__click:example" data-type='success' data-day='-2' class='btn btn-default btn-sm'>Success with date (-2 days)</button> <button data-bind="null__click:example" data-type='warning' data-day='-5' class='btn btn-default btn-sm'>Warning with date (-5 days)</button> <button data-bind="null__click:example" data-type='error' data-day='0' class='btn btn-default btn-sm'>Error with date (current)</button> <button data-bind="null__click:example" data-type='no' data-day='2' class='btn btn-default btn-sm'>No Type with date(+2 days)</button> <hr> Toast with with special icon:<br> <button data-bind="null__click:example" data-type='success' data-day='-2' data-icon='thermometer-full' class='btn btn-default btn-sm'>Success with icon and date</button> <button data-bind="null__click:example" data-type='no' data-icon='battery-quarter' class='btn btn-default btn-sm'>No Type with icon without date</button> <hr> Toast with with image:<br> <button data-bind="null__click:example" data-type='error' data-img='test' data-day='2' class='btn btn-default btn-sm'>Error with date (current)</button> <button data-bind="null__click:example" data-type='no' data-img='test' class='btn btn-default btn-sm'>No Type with icon without date</button> <hr> Toast with with special timeout:<br> <button data-bind="null__click:example" data-type='success' data-day='2' data-timeout='10' class='btn btn-default btn-sm'>Success</button> <button data-bind="null__click:example" data-type='no' data-icon='battery-quarter' data-timeout='15' class='btn btn-default btn-sm'>No Type with icon without date</button> <hr> Toast with callback:<br> <button data-bind="null__click:example_callback" class='btn btn-default btn-sm'>Success</button> </div> </div> <div class='col-md-4'> <div class="panel panel-default" style='margin: 20px 0; padding:10px;'> <b>Reconfigure</b><br><br> Change position:<br> <button data-bind="null__click:reconfigure" data-position='top-center' class='btn btn-default btn-sm'>top center</button> <button data-bind="null__click:reconfigure" data-position='bottom-center' class='btn btn-default btn-sm'>bottom center</button> <button data-bind="null__click:reconfigure" data-position='top-full-width' class='btn btn-default btn-sm'>top full width</button> <button data-bind="null__click:reconfigure" data-position='bottom-full-width' class='btn btn-default btn-sm'>bottom full width</button> <button data-bind="null__click:reconfigure" data-position='top-left' class='btn btn-default btn-sm'>top left</button> <button data-bind="null__click:reconfigure" data-position='top-right' class='btn btn-default btn-sm'>top right</button> <button data-bind="null__click:reconfigure" data-position='bottom-right' class='btn btn-default btn-sm'>bottom right</button> <button data-bind="null__click:reconfigure" data-position='bottom-left' class='btn btn-default btn-sm'>bottom left</button> <button data-bind="null__click:reconfigure" data-position='bottom-center' class='btn btn-default btn-sm'>bottom center</button> <button data-bind="null__click:reconfigure" data-position='bottom-full-width' class='btn btn-default btn-sm'>bottom full width</button> <hr> Animate:<br> <button data-bind="null__click:reconfigure" data-animate='fade' class='btn btn-default btn-sm'>fade</button> <button data-bind="null__click:reconfigure" data-animate='slide' class='btn btn-default btn-sm'>slide</button> <hr> Loader:<br> <button data-bind="null__click:reconfigure" data-loader='yes' class='btn btn-default btn-sm'>yes</button> <button data-bind="null__click:reconfigure" data-loader='no' class='btn btn-default btn-sm'>no</button> <hr> Timeout view:<br> <button data-bind="null__click:reconfigure" data-timeout='5' class='btn btn-default btn-sm'>5 sec</button> <button data-bind="null__click:reconfigure" data-timeout='10' class='btn btn-default btn-sm'>10 sec</button> <button data-bind="null__click:reconfigure" data-timeout='15' class='btn btn-default btn-sm'>15 sec</button> </div> </div> </div> </div> </div> </div> <script src='http://devanswer.com/codes/files/spa.min@18.js'></script><a style="font-size: 8pt; text-decoration: none" target="_blank" href="http://www.devanswer.com">Developer Code</a>

CSS
/* Notifications */
.ui-toast-container {
    position: fixed;
    z-index: 10000;
    padding: 5px 5px 0 0;
}

    .ui-toast-container.top-center {
        top: 0;
        right: 0;
        width: 100%
    }

    .ui-toast-container.bottom-center {
        bottom: 0;
        right: 0;
        width: 100%
    }

    .ui-toast-container.top-full-width {
        top: 0;
        right: 0;
        width: 100%
    }

    .ui-toast-container.bottom-full-width {
        bottom: 0;
        right: 0;
        width: 100%
    }

    .ui-toast-container.top-left {
        top: 12px;
        left: 12px
    }

    .ui-toast-container.top-right {
        top: 12px;
        right: 12px
    }

    .ui-toast-container.bottom-right {
        right: 12px;
        bottom: 12px
    }

    .ui-toast-container.bottom-left {
        bottom: 12px;
        left: 12px
    }

    .ui-toast-container.bottom-center > div, .ui-toast-container.top-center > div {
        width: 300px;
        margin-left: auto;
        margin-right: auto
    }

    .ui-toast-container.bottom-full-width > div, .ui-toast-container.top-full-width > div {
        width: 96%;
        margin-left: auto;
        margin-right: auto
    }

    .ui-toast-container > div {
        width: 300px;
    }

.ui-toast {
    background-color: white;
    box-shadow: 0 0 3px #999;
    border-radius: 3px;
    font-size: 14px;
    padding: 15px 15px 15px 10px;
    margin: 0 0 6px;
    position: relative;
    display: flex;
    opacity: .9;
}

    .ui-toast .loader {
        display: block;
        width: 0%;
        position: absolute;
        left: 0;
        bottom: 0;
        height: 4px; /*background-color:#000;opacity:.4;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=40);filter:alpha(opacity=40)*/
    }

    .ui-toast .loaded {
        width: 100%;
    }

    .ui-toast:hover {
        -moz-box-shadow: 0 0 4px #999;
        -webkit-box-shadow: 0 0 4px #999;
        box-shadow: 0 0 4px #999;
        opacity: 1;
        -ms-filter: alpha(opacity=100);
        filter: alpha(opacity=100);
    }

    .ui-toast > i {
        position: absolute;
        right: 12px;
        top: 10px;
        color: #AAB2BD;
        font-size: 14px;
        cursor: pointer;
        text-shadow: 0 1px 0 #fff;
        opacity: .8;
    }

        .ui-toast > i:active {
            top: 11px;
        }

        .ui-toast > i:hover {
            color: #000;
            text-decoration: none;
            cursor: pointer;
            opacity: .4;
            -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=40);
            filter: alpha(opacity=40)
        }

.ui-toast-icon {
    float: left;
    font-size: 24px;
    color: #AAB2BD;
    line-height: 24px; /*padding-right:0.5em;*/
    margin: auto 0.1em;
}

.ui-toast-message {
    margin: 1px 0 0 10px;
    color: gray;
    max-height: 150px;
}

.ui-toast-datetime {
    font-size: 10px;
    color: #A0A0A0;
    margin-bottom: 4px;
    padding-top: 5px;
}

.ui-toast.success {
    background-color: #1ab394;
}

.ui-toast.error {
    background-color: #ed5565;
}

.ui-toast.info {
    background-color: #2f96b4;
}

.ui-toast.warning {
    background-color: #F89406;
}

    .ui-toast.success > i, .ui-toast.error > i, .ui-toast.info > i, .ui-toast.warning > i {
        color: #fff;
    }

        .ui-toast.success > i:hover, .ui-toast.error > i:hover, .ui-toast.info > i:hover, .ui-toast.warning > i:hover {
            color: #000;
            text-decoration: none;
            opacity: .4;
            -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=40);
            filter: alpha(opacity=40)
        }

    .ui-toast.success .ui-toast-icon, .ui-toast.error .ui-toast-icon, .ui-toast.info .ui-toast-icon, .ui-toast.warning .ui-toast-icon {
        color: #fff;
    }

    .ui-toast.success .ui-toast-message, .ui-toast.error .ui-toast-message, .ui-toast.info .ui-toast-message, .ui-toast.warning .ui-toast-message {
        color: #fff;
    }

    .ui-toast.success .ui-toast-datetime, .ui-toast.error .ui-toast-datetime, .ui-toast.info .ui-toast-datetime, .ui-toast.warning .ui-toast-datetime {
        color: #F5F5F5;
    }

{
    color: #E0E0E0;
}
Javascript
COMPONENT('toast', 'timeout:8; position:top-right; loader:true; animate:fade', function (self, config) {
    self.singleton();
    self.readonly();
    self.template = Tangular.compile('<div class="ui-toast {{ type }}" data-id="{{ id }}" {{ if callback }} style="cursor:pointer"{{ fi }}>{{ if loader }}<div class="loader"></div>{{fi}}<i class="fa fa-times"></i><div class="ui-toast-icon">{{if icon }}<i class="fa {{ icon }}"></i>{{fi}}{{if img }}{{ img | raw }}{{fi}}</div><div class="ui-toast-message">{{if date }}<div class="ui-toast-datetime">{{ date }}</div>{{fi}}{{ mess | raw }}</div></div>');
    self.items = {};
    self.make = function () {
        self.aclass('ui-toast-container');
        let position = config.position || 'top-right';
        self.aclass(position);

        self.event('click', 'a,button', function (e) {
            e.stopPropagation();
        });

        self.event('click', '.ui-toast', function () {
            var el = $(this);
            var id = el.attr('data-id');
            var obj = self.items[id];
            self.close(obj.id);
        });
    };

    self.configure = function (key, value, init, prev) {
        if (init)
            return;
        if (key == 'position') {
            self.rclass();
            self.aclass('ui-toast-container ' + value);
        }
    }

    self.close = function (id) {
        var obj = self.items[id];
        if (obj.autoClose) clearTimeout(obj.autoClose);
        if (!obj) return;
        if (obj.callback) obj.callback(obj);
        obj.callback = null;
        delete self.items[id];
        if (config.animate == 'fade') {
            self.find('div[data-id="{0}"]'.format(id)).fadeOut('normal', function () { $(this).remove() });
        } else if (config.animate == 'slide') {
            self.find('div[data-id="{0}"]'.format(id)).slideUp('normal', function () { $(this).remove() });
        }
        else {
            self.find('div[data-id="{0}"]'.format(id)).remove();
        }
    };

    self.success = function (mess, o, callback) {
        self.append(mess, o, callback || null, 'success', 'check');
    };
    self.warning = function (mess, o, callback) {
        self.append(mess, o, callback || null, 'warning', 'exclamation-triangle');
    };
    self.error = function (mess, o, callback) {
        self.append(mess, o, callback || null, 'error', 'bell');
    };
    self.info = function (mess, o, callback) {
        self.append(mess, o, callback || null, 'info', 'info-circle');
    };

    self.append = function (mess, o, callback, tp, ic) {
        console.log(config);
        if (typeof (o) === 'function') {
            callback = o;
            o = null;
        }
        if (!o) o = {};
        o.type = o.type || tp || null;
        o.icon = o.icon || ic || null;
        let id = o.id || Math.floor(Math.random() * 100000);
        let type = (o.type) ? o.type : '';
        let icon = (o.icon) ? 'fa-' + o.icon : null;
        let img = (o.img) ? "<img class='img-rounded img-responsive' src='" + o.img + "'>" : null;
        let date = (o.date) ? o.date.format(config.format) : (config.dateAlways) ? new Date().format(config.format) : null;

        var obj = { id: id, type: type, icon: icon, img: img, mess: mess, date: date, callback: callback };
        obj.timeout = o.timeout || config.timeout;
        if (obj.timeout) obj.timeout *= 1000;
        obj.loader = o.loader || config.loader;
        self.items[obj.id] = obj;
        var elem = self.template(obj);
        self.element.append(elem);

        if (config.animate == 'fade') {
            self.element.find('.ui-toast:last').hide().fadeIn();
        } else if (config.animate == 'slide') {
            self.element.find('.ui-toast:last').hide().slideDown();
        }
        if (obj.loader) {
            self.updateLoader(obj);
        }
        if (obj.timeout) self.autoclose(obj);
    };

    self.updateLoader = function (obj) {
        var el = self.find('.ui-toast[data-id="' + obj.id + '"] .loader');
        var transitionTime = (obj.timeout / 1000) + 's';
        var style = '';
        style += '-webkit-transition: width ' + transitionTime + ' ease-in; \
                -o-transition: width ' + transitionTime + ' ease-in; \
                transition: width ' + transitionTime + ' ease-in; \
                background-color: #000; \
                opacity:.4;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=40);filter:alpha(opacity=40);';
        el.attr('style', style);
        setTimeout(function () { el.aclass('loaded'); }, 300);
    };

    self.autoclose = function (obj) {
        obj.autoClose = setTimeout(function () {
            self.close(obj.id);
        }, obj.timeout);
    };
})

//Test and example
var toast;
FIND('toast', function (comp) {
    toast = comp;
});

function example(e) {
    var str = [
        '<b>Title</b><br>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod',
        'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod'
    ];
    var ind = getRandom(2);
    var options = {};
    if (parseInt(e.data('day')) > -100) {
        options.date = new Date().add(e.data('day') + ' day');
    }

    if (e.data('icon')) {
        options.icon = e.data('icon');
    }

    if (e.data('img')) {
        options.img = '#';
    }

    if (e.data('timeout')) {
        options.timeout = e.data('timeout');
    }

    switch (e.data('type')) {
        case 'success': toast.success(str[ind], options); break;
        case 'warning': toast.warning(str[ind], options); break;
        case 'error': toast.error(str[ind], options); break;
        case 'info': toast.info(str[ind], options); break;
        default: toast.append(str[ind], options);
    }
}

function reconfigure(e) {
    if (e.data('position')) {
        RECONFIGURE('toast', { position: e.data('position') });
    }
    if (e.data('animate')) {
        RECONFIGURE('toast', { animate: e.data('animate') });
    }
    if (e.data('loader')) {
        var loader = (e.data('loader') == 'yes') ? true : false;
        RECONFIGURE('toast', { loader: loader });
    }
    if (e.data('timeout')) {
        RECONFIGURE('toast', { timeout: e.data('timeout') });
    }
}

function example_callback(e) {
    var str = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod';
    toast.error(str, { 'icon': 'battery-empty' }, function (res) {
        alert('Close notify - ' + res.mess);
    });
}

function getRandom(max) {
    return Math.floor(Math.random() * Math.floor(max));
}