Toast
Non-intrusive notification components for feedback and status updates with auto-dismiss functionality.
Toast Types
Success Toast
Error Toast
Warning Toast
Info Toast
Toast with Progress
Persistent Toast
Static Examples
Implementation Guide
HTML Structure
<!-- Toast Container -->
<div class="lyd-toast-container">
<!-- Success Toast -->
<div class="lyd-toast success">
<svg class="lyd-toast-icon">...</svg>
<div class="lyd-toast-content">
<div class="lyd-toast-title">Success!</div>
<div class="lyd-toast-message">Operation completed successfully.</div>
</div>
<button class="lyd-toast-close">
<svg>...</svg>
</button>
</div>
<!-- Toast with Progress -->
<div class="lyd-toast info">
<svg class="lyd-toast-icon">...</svg>
<div class="lyd-toast-content">
<div class="lyd-toast-title">Processing</div>
<div class="lyd-toast-message">Please wait...</div>
</div>
<div class="lyd-toast-progress"></div>
</div>
</div>
JavaScript Functions
// Toast Manager
class ToastManager {
constructor() {
this.container = null;
this.init();
}
init() {
// Create container if it doesn't exist
if (!document.querySelector('.lyd-toast-container')) {
this.container = document.createElement('div');
this.container.className = 'lyd-toast-container';
document.body.appendChild(this.container);
} else {
this.container = document.querySelector('.lyd-toast-container');
}
}
show(type, title, message, duration = 5000) {
const toast = document.createElement('div');
toast.className = `lyd-toast ${type}`;
const icons = {
success: '<path d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />',
error: '<path d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" />',
warning: '<path d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />',
info: '<path d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />'
};
toast.innerHTML = `
<svg class="lyd-toast-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor">
${icons[type]}
</svg>
<div class="lyd-toast-content">
<div class="lyd-toast-title">${title}</div>
<div class="lyd-toast-message">${message}</div>
</div>
<button class="lyd-toast-close">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
${duration > 0 ? '<div class="lyd-toast-progress"></div>' : ''}
`;
this.container.appendChild(toast);
// Close button
toast.querySelector('.lyd-toast-close').addEventListener('click', () => {
this.hide(toast);
});
// Auto dismiss
if (duration > 0) {
setTimeout(() => {
this.hide(toast);
}, duration);
}
}
hide(toast) {
toast.classList.add('hiding');
setTimeout(() => {
toast.remove();
}, 300);
}
}
// Initialize
const toastManager = new ToastManager();
// Helper functions
function showToast(type) {
const messages = {
success: { title: 'Success!', message: 'Operation completed successfully.' },
error: { title: 'Error!', message: 'Something went wrong. Please try again.' },
warning: { title: 'Warning!', message: 'Please check your input.' },
info: { title: 'Info', message: 'Here\'s some useful information.' }
};
toastManager.show(type, messages[type].title, messages[type].message);
}
React/Next.js Component
// components/Toast.tsx
import { useState, useEffect } from 'react';
import { createPortal } from 'react-dom';
interface ToastProps {
type: 'success' | 'error' | 'warning' | 'info';
title: string;
message: string;
duration?: number;
onClose: () => void;
}
export const Toast = ({ type, title, message, duration = 5000, onClose }: ToastProps) => {
const [isVisible, setIsVisible] = useState(true);
useEffect(() => {
if (duration > 0) {
const timer = setTimeout(() => {
setIsVisible(false);
setTimeout(onClose, 300);
}, duration);
return () => clearTimeout(timer);
}
}, [duration, onClose]);
const icons = {
success: 'M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z',
error: 'M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z',
warning: 'M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z',
info: 'M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z'
};
return createPortal(
<div className={`lyd-toast ${type} ${!isVisible ? 'hiding' : ''}`}>
<svg className="lyd-toast-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d={icons[type]} />
</svg>
<div className="lyd-toast-content">
<div className="lyd-toast-title">{title}</div>
<div className="lyd-toast-message">{message}</div>
</div>
<button className="lyd-toast-close" onClick={() => {
setIsVisible(false);
setTimeout(onClose, 300);
}}>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
{duration > 0 && <div className="lyd-toast-progress" />}
</div>,
document.body
);
};
API Reference
| Class | Description |
|---|---|
.lyd-toast-container |
Container for toast notifications |
.lyd-toast |
Individual toast notification |
.lyd-toast-icon |
Toast type icon |
.lyd-toast-content |
Content wrapper |
.lyd-toast-title |
Toast title text |
.lyd-toast-message |
Toast message text |
.lyd-toast-close |
Close button |
.lyd-toast-progress |
Auto-dismiss progress bar |
.success |
Success toast styling |
.error |
Error toast styling |
.warning |
Warning toast styling |
.info |
Info toast styling |
Accessibility & Best Practices
Accessibility Features
- ARIA live regions for screen readers
- Keyboard dismissible (Escape key)
- Focus management
- Sufficient color contrast
Best Practices
- Keep messages concise and actionable
- Use appropriate types for context
- Auto-dismiss after 5-7 seconds
- Allow manual dismissal
- Stack multiple toasts vertically
- Position consistently (top-right recommended)