NOT001

Notification Toast

A modern, animated notification toast system with multiple styles

JavaScript
Font Awesome Included: This snippet uses Font Awesome icons. The required stylesheet is automatically included at the top of the code block. If you are going to use this snippet in your project, add the stylesheet to your <head>.

Live Preview

Code

HTML
<!-- Font Awesome Icons; Make sure to add it in the <head> tag -->
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
  
<!-- Toast container where notifications will appear -->
<div class="toast-container"></div>

<!-- Example buttons to trigger different toast types -->
<button onclick="showToast('success', 'Success!', 'Operation completed successfully.')">Success</button>
<button onclick="showToast('error', 'Error!', 'Something went wrong.')">Error</button>
<button onclick="showToast('info', 'Info', 'Here is some information.')">Info</button>
<button onclick="showToast('warning', 'Warning', 'Please be careful.')">Warning</button>
CSS
.toast-container {
  position: fixed;
  top: 20px;
  right: 20px;
  z-index: 9999;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.toast {
  display: flex;
  align-items: center;
  min-width: 300px;
  max-width: 400px;
  background-color: white;
  color: #333;
  border-radius: 8px;
  padding: 16px;
  margin-bottom: 8px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  transform: translateX(120%);
  transition: transform 0.3s ease;
  overflow: hidden;
  position: relative;
}

.toast.show {
  transform: translateX(0);
}

.toast-icon {
  margin-right: 12px;
  font-size: 20px;
  min-width: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.toast-content {
  flex-grow: 1;
  padding-right: 10px;
}

.toast-title {
  font-weight: 600;
  margin-bottom: 4px;
  font-size: 16px;
}

.toast-message {
  font-size: 14px;
  color: #666;
}

.toast-close {
  background: none;
  border: none;
  color: #888;
  cursor: pointer;
  font-size: 16px;
  padding: 4px;
  transition: color 0.2s;
}

.toast-close:hover {
  color: #333;
}

.toast-progress {
  position: absolute;
  bottom: 0;
  left: 0;
  height: 4px;
  width: 100%;
  transform-origin: left;
}

/* Toast types */
.toast.success {
  border-left: 4px solid #4caf50;
}

.toast.success .toast-icon {
  color: #4caf50;
}

.toast.success .toast-progress {
  background-color: #4caf50;
}

.toast.error {
  border-left: 4px solid #f44336;
}

.toast.error .toast-icon {
  color: #f44336;
}

.toast.error .toast-progress {
  background-color: #f44336;
}

.toast.info {
  border-left: 4px solid #2196f3;
}

.toast.info .toast-icon {
  color: #2196f3;
}

.toast.info .toast-progress {
  background-color: #2196f3;
}

.toast.warning {
  border-left: 4px solid #ff9800;
}

.toast.warning .toast-icon {
  color: #ff9800;
}

.toast.warning .toast-progress {
  background-color: #ff9800;
}

/* Dark mode styling */
@media (prefers-color-scheme: dark) {
  .toast {
    background-color: #333;
    color: #eee;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
  }
  
  .toast-message {
    color: #bbb;
  }
  
  .toast-close {
    color: #aaa;
  }
  
  .toast-close:hover {
    color: #eee;
  }
}
JavaScript
/**
 * Show a toast notification
 * @param {string} type - Type of toast: 'success', 'error', 'info', 'warning'
 * @param {string} title - Toast title
 * @param {string} message - Toast message
 * @param {number} duration - Duration in milliseconds (default: 5000ms)
 */
function showToast(type, title, message, duration = 5000) {
  // Create toast element
  const toast = document.createElement('div');
  toast.className = `toast ${type}`;
  
  // Set icon based on type
  let icon = '';
  switch(type) {
    case 'success':
      icon = 'fa-circle-check';
      break;
    case 'error':
      icon = 'fa-circle-xmark';
      break;
    case 'info':
      icon = 'fa-circle-info';
      break;
    case 'warning':
      icon = 'fa-triangle-exclamation';
      break;
    default:
      icon = 'fa-bell';
  }
  
  // Create toast HTML structure
  toast.innerHTML = `
    <div class="toast-icon">
      <i class="fas ${icon}"></i>
    </div>
    <div class="toast-content">
      <div class="toast-title">${title}</div>
      <div class="toast-message">${message}</div>
   </div>
    <button class="toast-close">
      <i class="fas fa-times"></i>
    </button>
    <div class="toast-progress"></div>
  `;
  
  // Get the container
  const container = document.querySelector('.toast-container');
  
  // If container doesn't exist, create it
  if (!container) {
    const newContainer = document.createElement('div');
    newContainer.className = 'toast-container';
    document.body.appendChild(newContainer);
    newContainer.appendChild(toast);
  } else {
    container.appendChild(toast);
  }
  
  // Add closing functionality
  const closeButton = toast.querySelector('.toast-close');
  closeButton.addEventListener('click', () => {
    closeToast(toast);
  });
  
  // Animate progress bar
  const progress = toast.querySelector('.toast-progress');
  progress.style.animation = `progress-shrink ${duration/1000}s linear forwards`;
  
  // Set timeout to remove toast
  setTimeout(() => {
    closeToast(toast);
  }, duration);
  
  // Make the toast appear after a short delay (for animation)
  setTimeout(() => {
    toast.classList.add('show');
  }, 10);
}

/**
 * Close and remove a toast
 * @param {HTMLElement} toast - The toast element to close
 */
function closeToast(toast) {
  toast.classList.remove('show');
  
  // Wait for the animation to finish before removing
  setTimeout(() => {
    if (toast.parentElement) {
      toast.parentElement.removeChild(toast);
    }
  }, 300);
}

// Add CSS keyframes for progress bar
const style = document.createElement('style');
style.textContent = `
  @keyframes progress-shrink {
    0% { transform: scaleX(1); }
    100% { transform: scaleX(0); }
  }
`;
document.head.appendChild(style);