Stacking Toast Notifications
Toasts that stack with colour-coded SVG icons, an auto-dismiss progress bar and manual close.
<div class="toast-demo">
<button data-type="success">Success</button>
<button data-type="error">Error</button>
<button data-type="info">Info</button>
</div>
<div class="toast-stack" id="stack"></div>*{box-sizing:border-box}
.toast-demo{display:flex;gap:10px;justify-content:center;font-family:system-ui,sans-serif}
.toast-demo button{padding:10px 18px;border:0;border-radius:10px;font-weight:700;cursor:pointer;color:#fff;transition:transform .12s}
.toast-demo button:active{transform:scale(.96)}
.toast-demo button[data-type=success]{background:#16a34a}
.toast-demo button[data-type=error]{background:#ef4444}
.toast-demo button[data-type=info]{background:#5b6cff}
.toast-stack{position:fixed;top:18px;right:18px;display:flex;flex-direction:column;gap:10px;z-index:50}
.tt{position:relative;display:flex;align-items:center;gap:11px;min-width:250px;background:#fff;border-radius:12px;padding:14px 40px 14px 14px;box-shadow:0 10px 30px rgba(20,25,50,.18);font-family:system-ui,sans-serif;font-weight:600;color:#1a1f36;overflow:hidden;transform:translateX(120%);transition:transform .35s cubic-bezier(.5,0,.2,1)}
.tt.in{transform:none}
.tt-ic{flex:none;width:26px;height:26px;border-radius:50%;display:grid;place-items:center;color:#fff}
.tt.success .tt-ic{background:#16a34a}.tt.error .tt-ic{background:#ef4444}.tt.info .tt-ic{background:#5b6cff}
.tt-x{position:absolute;top:50%;right:10px;transform:translateY(-50%);border:0;background:0;color:#b6bccb;cursor:pointer;display:grid;place-items:center;padding:4px}
.tt-prog{position:absolute;left:0;bottom:0;height:3px;width:100%;animation:shrink 3.2s linear forwards}
.tt.success .tt-prog{background:#16a34a}.tt.error .tt-prog{background:#ef4444}.tt.info .tt-prog{background:#5b6cff}
@keyframes shrink{to{width:0}}var stack=document.getElementById('stack');
var ICON={
success:'<svg viewBox="0 0 24 24" width="16" height="16"><path fill="none" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4 10-11"/></svg>',
error:'<svg viewBox="0 0 24 24" width="16" height="16"><path fill="none" stroke="#fff" stroke-width="3" stroke-linecap="round" d="M7 7l10 10M17 7L7 17"/></svg>',
info:'<svg viewBox="0 0 24 24" width="16" height="16"><path fill="none" stroke="#fff" stroke-width="3" stroke-linecap="round" d="M12 11v6M12 7.5v.5"/></svg>'
};
var MSG={success:'Saved successfully',error:'Something went wrong',info:'Heads up, just so you know'};
var CLOSE='<svg viewBox="0 0 24 24" width="16" height="16"><path fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" d="M6 6l12 12M18 6L6 18"/></svg>';
function toast(type){
var t=document.createElement('div');t.className='tt '+type;
t.innerHTML='<span class="tt-ic">'+ICON[type]+'</span><span>'+MSG[type]+'</span><button class="tt-x" aria-label="Close">'+CLOSE+'</button><span class="tt-prog"></span>';
stack.appendChild(t);requestAnimationFrame(function(){t.classList.add('in')});
var to=setTimeout(close,3200);
function close(){clearTimeout(to);t.classList.remove('in');setTimeout(function(){t.remove()},350)}
t.querySelector('.tt-x').onclick=close;
}
document.querySelectorAll('.toast-demo button').forEach(function(b){b.onclick=function(){toast(b.dataset.type)}});Free to use.This snippet is plain HTML, CSS and JavaScript with no dependencies. Copy any file, or download the whole thing as a single ready-to-open .html page.