Skip to content

Instantly share code, notes, and snippets.

@cferdinandi
Created April 1, 2025 18:01
Show Gist options
  • Save cferdinandi/cf287f1c404872291b4120a17f6617e7 to your computer and use it in GitHub Desktop.
Save cferdinandi/cf287f1c404872291b4120a17f6617e7 to your computer and use it in GitHub Desktop.
Watch the tutorial on YouTube: https://youtu.be/v-3O0MCl41k
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Toast Library</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body {
margin: 1em auto;
width: 88%;
max-width: 40em;
min-height: 100vh;
}
</style>
<link rel="stylesheet" type="text/css" href="toast.css">
</head>
<body>
<h1>Toast Library</h1>
<button>Add a Thing</button>
<div class="notify-wrapper"></div>
<script src="toast.js"></script>
<script>
let btn = document.querySelector('button');
btn.addEventListener('click', function () {
console.log('thing added!');
let notification = new Notify('.notify-wrapper', 'Your thing was added!', {
type: 'info', // info || success || error || warning
noClose: false, // true || false
// duration: 0, // how long to persist in milliseconds (-1 for forever)
});
notification.show();
// notification.dismiss();
notification.notification.addEventListener('notify:before-dismiss', (event) => {
if (!someOtherCondition) {
event.preventDefault();
}
});
});
function log (event) {
console.log(event.type, event.target);
}
document.addEventListener('notify:before-show', log);
document.addEventListener('notify:show', log);
document.addEventListener('notify:before-dismiss', function (event) {
log(event);
event.preventDefault();
});
document.addEventListener('notify:dismiss', log);
</script>
</body>
</html>
/**
* @section Toast styles
*/
.notify-wrapper {
position: fixed;
left: 0;
bottom: 0;
width: 100%;
}
.notify {
background-color: #272727;
border-radius: 1em;
color: #ffffff;
padding: 0.5em 1em;
margin: 0.25em auto;
width: 88%;
max-width: 30em;
}
.notify-info {
background-color: #007ab8;
}
.notify-success {
background-color: green;
}
.notify-error {
background-color: red;
}
.notify-close {
cursor: pointer;
float: right;
background: transparent;
border: none;
padding-left: 0.25em;
height: 1em;
width: 1em;
}
.notify-close:before {
content: "X";
color: #ffffff;
}
// Toast JS
class Notify {
/**
* Instantiate the library
* @param {String | Element} selector The target location to render the notification
* @param {String} message The message to render into the UI
* @param {Object} options The library options
*/
constructor (selector, message, options = {}) {
// Get the target to render into
this.target = typeof selector === 'string' ? document.querySelector(selector) : selector;
if (!this.target) {
console.warn('NotifyJS: Target element not found');
return;
}
if (!message) {
console.warn('NotifyJS: Please provide a message');
return;
}
this.message = message;
this.type = options.type || 'info'; // info || success || error || warning
this.noClose = !!options.noClose; // true || false
this.duration = options.duration ?? 3000; // how long to persist in milliseconds (-1 for forever)
this.closeMessage = options.closeMessage || 'Close Notification';
}
/**
* Show the notification
*/
show () {
// Only run if target and message are provided
if (!this.target || !this.message) return;
// Create the notification message
this.notification = document.createElement('div');
this.notification.className = `notify notify-${this.type}`;
this.notification.setAttribute('role', 'status');
// Add it to the DOM
this.target.prepend(this.notification);
if (!this.emit('before-show')) return;
// Update the text
setTimeout(() => {
this.notification.textContent = this.message;
this.emit('show');
}, 1);
// Automatically dismiss the notification
if (this.duration > 0) {
setTimeout(() => {
this.dismiss();
}, this.duration);
}
// If user can't close, nothing else to do
if (this.noClose) return;
// Create close button
let btn = document.createElement('button');
btn.className = 'notify-close';
btn.setAttribute('aria-label', this.closeMessage);
setTimeout(() => {
this.notification.prepend(btn);
}, 2);
// Listen for button clicks, and dismiss the notification
btn.addEventListener('click', () => {
this.dismiss();
});
}
/**
* Dismiss the notification
*/
dismiss () {
// Only run if target and message are provided
if (!this.target || !this.message || !this.notification) return;
if (!this.emit('before-dismiss')) return;
// Remove the notification from the DOM
this.emit('dismiss');
this.notification.remove();
}
/**
* Emit a custom event
* @param {String} type The event type
*/
emit (type) {
// Make sure there's an event type
if (!type) return;
// Create a new event
let event = new CustomEvent(`notify:${type}`, {
bubbles: true,
cancelable: true
});
// Dispatch the event
return this.notification.dispatchEvent(event);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment