This code provides an example of a JavaScript toast message implementation. Toast messages are non-intrusive notifications that appear temporarily on the screen to provide feedback or important information to the user.
The code creates a `NotificationCenter` class that handles the spawning and management of toast notifications. Each notification can have an icon, title, subtitle, and action. The notifications are displayed on the screen and can be dismissed by clicking on them.
The code also includes a set of predefined notification messages that can be customized or expanded upon. This code can be helpful for developers who want to add toast message functionality to their web applications or websites.
How to Create JavaScript Toast Message
To load Google Fonts, add the following CDN links to the head tag of your HTML document.
<link rel='stylesheet' href='https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;700&display=swap'>
Copy the SVG code below and paste it within the body tag to use these symbols in your notifications.
<svg display="none"> <symbol id="clock" viewBox="0 0 32 32" > <circle r="15" cx="16" cy="16" fill="none" stroke="currentColor" stroke-width="2" /> <polyline points="16,7 16,16 23,16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> </symbol> <symbol id="error" viewBox="0 0 32 32" > <circle r="15" cx="16" cy="16" fill="none" stroke="hsl(13,90%,55%)" stroke-width="2" /> <line x1="10" y1="10" x2="22" y2="22" stroke="hsl(13,90%,55%)" stroke-width="2" stroke-linecap="round" /> <line x1="22" y1="10" x2="10" y2="22" stroke="hsl(13,90%,55%)" stroke-width="2" stroke-linecap="round" /> </symbol> <symbol id="message" viewBox="0 0 32 32" > <polygon points="1,6 31,6 31,26 1,26" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> <polyline points="1,6 16,18 31,6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> </symbol> <symbol id="success" viewBox="0 0 32 32" > <circle r="15" cx="16" cy="16" fill="none" stroke="hsl(93,90%,40%)" stroke-width="2" /> <polyline points="9,18 13,22 23,12" fill="none" stroke="hsl(93,90%,40%)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> </symbol> <symbol id="up" viewBox="0 0 32 32" > <circle r="15" cx="16" cy="16" fill="none" stroke="currentColor" stroke-width="2" /> <polyline points="11,15 16,10 21,15" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> <line x1="16" y1="10" x2="16" y2="22" stroke="currentColor" stroke-width="2" stroke-linecap="round" /> </symbol> <symbol id="warning" viewBox="0 0 32 32" > <polygon points="16,1 31,31 1,31" fill="none" stroke="hsl(33,90%,55%)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> <line x1="16" y1="12" x2="16" y2="20" stroke="hsl(33,90%,55%)" stroke-width="2" stroke-linecap="round" /> <line x1="16" y1="25" x2="16" y2="25" stroke="hsl(33,90%,55%)" stroke-width="3" stroke-linecap="round" /> </symbol> </svg>
Use the following CSS styles to customize the appearance of the toast messages:
* { border: 0; box-sizing: border-box; margin: 0; padding: 0; } :root { --hue: 223; --bg: hsl(var(--hue),10%,90%); --fg: hsl(var(--hue),10%,10%); --transDur: 0.15s; font-size: calc(16px + (24 - 16) * (100vw - 320px) / (1280 - 320)); } body, button { color: var(--fg); font: 1em/1.5 "DM Sans", "Helvetica Neue", Helvetica, sans-serif; } body { background-color: var(--bg); height: 100vh; display: grid; place-items: center; transition: background-color var(--transDur); } .notification { padding-bottom: 0.75em; position: fixed; top: 1.5em; right: 1.5em; width: 18.75em; max-width: calc(100% - 3em); transition: transform 0.15s ease-out; -webkit-user-select: none; -moz-user-select: none; user-select: none; } .notification__box, .notification__content, .notification__btns { display: flex; } .notification__box, .notification__content { align-items: center; } .notification__box { animation: flyIn 0.3s ease-out; background-color: hsl(0,0%,100%); border-radius: 0.75em; box-shadow: 0 0.5em 1em hsla(var(--hue),10%,10%,0.1); height: 4em; transition: background-color var(--transDur), color var(--transDur); } .notification--out .notification__box { animation: flyOut 0.3s ease-out forwards; } .notification__content { padding: 0.375em 1em; width: 100%; height: 100%; } .notification__icon { flex-shrink: 0; margin-right: 0.75em; width: 2em; height: 2em; } .notification__icon-svg { width: 100%; height: auto; } .notification__text { line-height: 1.333; } .notification__text-title { font-size: 0.75em; font-weight: bold; } .notification__text-subtitle { font-size: 0.6em; opacity: 0.75; } .notification__btns { box-shadow: -1px 0 0 hsla(var(--hue),10%,10%,0.15); flex-direction: column; flex-shrink: 0; min-width: 4em; height: 100%; transition: box-shadow var(--transDur); } .notification__btn { background-color: transparent; box-shadow: 0 0 0 hsla(var(--hue),10%,10%,0.5) inset; font-size: 0.6em; line-height: 1; font-weight: 500; height: 100%; padding: 0 0.5rem; transition: background-color var(--transDur), color var(--transDur); -webkit-appearance: none; appearance: none; -webkit-tap-highlight-color: transparent; } .notification__btn-text { display: inline-block; pointer-events: none; } .notification__btn:first-of-type { border-radius: 0 0.75rem 0 0; } .notification__btn:last-of-type { border-radius: 0 0 0.75rem 0; } .notification__btn:only-child { border-radius: 0 0.75rem 0.75rem 0; } .notification__btn + .notification__btn { box-shadow: 0 -1px 0 hsla(var(--hue),10%,10%,0.15); font-weight: 400; } .notification__btn:active, .notification__btn:focus { background-color: hsl(var(--hue),10%,95%); } .notification__btn:focus { outline: transparent; } @supports selector(:focus-visible) { .notification__btn:focus { background-color: transparent; } .notification__btn:focus-visible, .notification__btn:active { background-color: hsl(var(--hue),10%,95%); } } /* Dark theme */ @media (prefers-color-scheme: dark) { :root { --bg: hsl(var(--hue),10%,10%); --fg: hsl(var(--hue),10%,90%); } .notification__box { background-color: hsl(var(--hue),10%,30%); } .notification__btns { box-shadow: -1px 0 0 hsla(var(--hue),10%,90%,0.15); } .notification__btn + .notification__btn { box-shadow: 0 -1px 0 hsla(var(--hue),10%,90%,0.15); } .notification__btn:active, .notification__btn:focus { background-color: hsl(var(--hue),10%,35%); } @supports selector(:focus-visible) { .notification__btn:focus { background-color: transparent; } .notification__btn:focus-visible, .notification__btn:active { background-color: hsl(var(--hue),10%,35%); } } } /* Animations */ @keyframes flyIn { from { transform: translateX(calc(100% + 1.5em)); } to { transform: translateX(0); } } @keyframes flyOut { from { transform: translateX(0); } to { transform: translateX(calc(100% + 1.5em)); } }
Add the following JavaScript function to activate the toast notifications:
window.addEventListener("DOMContentLoaded",() => { const nc = new NotificationCenter(); }); class NotificationCenter { constructor() { this.items = []; this.itemsToKill = []; this.messages = NotificationMessages(); this.killTimeout = null; this.spawnNotes(3); } spawnNote() { const id = this.random(0,2**32,true).toString(16); const draw = this.random(0,this.messages.length - 1,true); const message = this.messages[draw]; const note = new Notification({ id: `note-${id}`, icon: message.icon, title: message.title, subtitle: message.subtitle, actions: message.actions }); const transY = 100 * this.items.length; note.el.style.transform = `translateY(${transY}%)`; note.el.addEventListener("click",this.killNote.bind(this,note.id)); this.items.push(note); } spawnNotes(amount) { let count = typeof amount === "number" ? amount : this.random(1,5,true); while (count--) this.spawnNote(); } killNote(id,e) { const note = this.items.find(item => item.id === id); const tar = e.target; if (note && tar.getAttribute("data-dismiss") === id) { note.el.classList.add("notification--out"); this.itemsToKill.push(note); clearTimeout(this.killTimeout); this.killTimeout = setTimeout(() => { this.itemsToKill.forEach(itemToKill => { document.body.removeChild(itemToKill.el); const left = this.items.filter(item => item.id !== itemToKill.id); this.items = [...left]; }); this.itemsToKill = []; if (!this.items.length) this.spawnNotes(); else this.spawnNotes(this.random(0,1,true)); this.shiftNotes(); },note.killTime); } } shiftNotes() { this.items.forEach((item,i) => { const transY = 100 * i; item.el.style.transform = `translateY(${transY}%)`; }); } random(min,max,round = false) { const percent = crypto.getRandomValues(new Uint32Array(1))[0] / 2**32; const relativeValue = (max - min) * percent; return min + (round === true ? Math.round(relativeValue) : +relativeValue.toFixed(2)); } } class Notification { constructor(args) { this.args = args; this.el = null; this.id = null; this.killTime = 300; this.init(args); } init(args) { const {id,icon,title,subtitle,actions} = args; const block = "notification"; const parent = document.body; const xmlnsSVG = "http://www.w3.org/2000/svg"; const xmlnsUse = "http://www.w3.org/1999/xlink"; const note = this.newEl("div"); note.id = id; note.className = block; parent.insertBefore(note,parent.lastElementChild); const box = this.newEl("div"); box.className = `${block}__box`; note.appendChild(box); const content = this.newEl("div"); content.className = `${block}__content`; box.appendChild(content); const _icon = this.newEl("div"); _icon.className = `${block}__icon`; content.appendChild(_icon); const iconSVG = this.newEl("svg",xmlnsSVG); iconSVG.setAttribute("class",`${block}__icon-svg`); iconSVG.setAttribute("role","img"); iconSVG.setAttribute("aria-label",icon); iconSVG.setAttribute("width","32px"); iconSVG.setAttribute("height","32px"); _icon.appendChild(iconSVG); const iconUse = this.newEl("use",xmlnsSVG); iconUse.setAttributeNS(xmlnsUse,"href",`#${icon}`); iconSVG.appendChild(iconUse); const text = this.newEl("div"); text.className = `${block}__text`; content.appendChild(text); const _title = this.newEl("div"); _title.className = `${block}__text-title`; _title.textContent = title; text.appendChild(_title); if (subtitle) { const _subtitle = this.newEl("div"); _subtitle.className = `${block}__text-subtitle`; _subtitle.textContent = subtitle; text.appendChild(_subtitle); } const btns = this.newEl("div"); btns.className = `${block}__btns`; box.appendChild(btns); actions.forEach(action => { const btn = this.newEl("button"); btn.className = `${block}__btn`; btn.type = "button"; btn.setAttribute("data-dismiss",id); const btnText = this.newEl("span"); btnText.className = `${block}__btn-text`; btnText.textContent = action; btn.appendChild(btnText); btns.appendChild(btn); }); this.el = note; this.id = note.id; } newEl(elName,NSValue) { if (NSValue) return document.createElementNS(NSValue,elName); else return document.createElement(elName); } } function NotificationMessages() { return [ { icon: "error", title: "Oh No", subtitle: "Something really bad happened.", actions: ["Close"] }, { icon: "error", title: "Error", subtitle: "The operation completed successfully.", actions: ["OK"] }, { icon: "error", title: "Critical Error", subtitle: "An error has occurred while trying to display an error notification.", actions: ["OK"] }, { icon: "warning", title: "Reminder", subtitle: "You will receive more notifications.", actions: ["Close"] }, { icon: "warning", title: "Failed to Save Changes", actions: ["Retry","Cancel"] }, { icon: "warning", title: "Download Failed", actions: ["Retry","Cancel"] }, { icon: "warning", title: "Cannot Send Mail", subtitle: "The message was rejected by the server because it is too large.", actions: ["OK"] }, { icon: "warning", title: "Disk Not Ejected Properly", subtitle: "Eject “CopyThisFloppy” before disconnecting or turning it off.", actions: ["Close"] }, { icon: "warning", title: "Notifications", subtitle: "Notifications may include alerts, sounds, and icon badges.", actions: ["Don’t Allow","Allow"] }, { icon: "success", title: "Changes Saved", actions: ["OK"] }, { icon: "success", title: "Download Complete", actions: ["OK"] }, { icon: "success", title: "Yippee", subtitle: "Nothing bad happened.", actions: ["OK"] }, { icon: "message", title: "Mail Password Required", subtitle: "Enter your password for user@domain.com.", actions: ["Close","Continue"] }, { icon: "message", title: "Mail", subtitle: "You have 10 new messages.", actions: ["Read","Dismiss"] }, { icon: "clock", title: "Coffee Break", subtitle: "In 5 minutes", actions: ["Close","Snooze"] }, { icon: "clock", title: "Muffin Time", subtitle: "12:30 PM", actions: ["Close","Snooze"] }, { icon: "clock", title: "Hammer Time", subtitle: "In 2 minutes", actions: ["Close","Snooze"] }, { icon: "up", title: "Upgrade Available", subtitle: "Enjoy the latest technologies and refinements to your favorite apps.", actions: ["Install","Details"] }, { icon: "up", title: "Upgrade Waiting", subtitle: "Get it now, or it won’t be long until you are far behind everyone else.", actions: ["Install","Details"] }, { icon: "up", title: "Upgrade Now", subtitle: "The current version will soon be obsolete. What are you waiting for?", actions: ["Install","Details"] } ]; }
Toast Notifications Customization
- Change the Notification Messages: The
NotificationMessages
function provides an array of predefined messages. You can modify this array to include your own custom messages. Each message object in the array should have the following properties:icon
: The icon for the notification. You can use existing icon names like “error,” “warning,” “success,” “message,” “clock,” or “up,” or you can add your own SVG icon.title
: The main title of the notification.subtitle
(optional): An optional subtitle for the notification.actions
: An array of action buttons for the notification. You can customize the button labels or add/remove buttons as needed.
- Modify the Notification Class: The
Notification
class represents an individual toast notification. You can modify theinit
method in this class to customize the structure and appearance of the notification. You can change the HTML elements, CSS classes, styles, or add additional elements as per your design requirements. - Styling with CSS: You can customize the appearance of the toast notifications by modifying the provided CSS classes. You can update the existing styles or add new styles to match your desired look and feel. You can find the CSS rules associated with the notification styling in your project’s CSS file.
That’s all! hopefully, you have successfully integrated this JavaScript toast message example into your project. If you have any questions or suggestions, feel free to comment below.