Compare 2 design variants side by side
: "The Soft Stack" (Elegant & Contextual)
<!DOCTYPE html>
<html lang="en">
<head>
<style>
:root {
--font-main: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
--color-bg: #ffffff;
--color-text-primary: #1f2937;
--color-text-secondary: #6b7280;
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
/* Semantic Colors */
--success: #10b981;
--error: #ef4444;
--info: #3b82f6;
--warning: #f59e0b;
}
body { font-family: var(--font-main); background: #f3f4f6; height: 100vh; margin: 0; display: flex; justify-content: center; align-items: center; }
/* Toast Container */
.toast-container-v1 {
position: fixed;
bottom: 24px;
left: 50%;
transform: translateX(-50%);
display: flex;
flex-direction: column;
gap: 12px;
z-index: 9999;
width: 90%;
max-width: 400px;
}
/* The Toast Card */
.toast-v1 {
background: var(--color-bg);
border-radius: 8px;
box-shadow: var(--shadow-lg);
display: flex;
align-items: flex-start;
padding: 16px;
position: relative;
overflow: hidden;
animation: slideUp 0.4s cubic-bezier(0.16, 1, 0.3, 1) forwards;
border: 1px solid rgba(0,0,0,0.05);
}
/* Status Strip */
.toast-v1::before {
content: '';
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 4px;
}
.toast-v1.success::before { background: var(--success); }
.toast-v1.error::before { background: var(--error); }
.toast-v1.info::before { background: var(--info); }
/* Icon Wrapper */
.toast-icon {
margin-right: 12px;
display: flex;
align-items: center;
padding-top: 2px;
}
.toast-v1.success .toast-icon { color: var(--success); }
.toast-v1.error .toast-icon { color: var(--error); }
/* Content */
.toast-content {
flex: 1;
padding-right: 12px;
}
.toast-title {
font-size: 14px;
font-weight: 600;
color: var(--color-text-primary);
margin: 0 0 4px 0;
}
.toast-message {
font-size: 13px;
color: var(--color-text-secondary);
margin: 0;
line-height: 1.4;
}
/* Actions */
.toast-action {
background: none;
border: none;
font-size: 13px;
font-weight: 600;
cursor: pointer;
margin-left: 8px;
padding: 4px 8px;
border-radius: 4px;
transition: background 0.2s;
}
.toast-v1.success .toast-action { color: var(--success); }
.toast-v1.success .toast-action:hover { background: #d1fae5; }
.toast-close {
background: transparent;
border: none;
color: #9ca3af;
cursor: pointer;
padding: 4px;
display: flex;
align-items: center;
border-radius: 4px;
}
.toast-close:hover {
background: #f3f4f6;
color: #4b5563;
}
/* Animations */
@keyframes slideUp {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes fadeOut {
to { opacity: 0; transform: translateY(-10px); }
}
/* Button for demo */
.trigger-btn { padding: 10px 20px; background: #1f2937; color: white; border: none; border-radius: 6px; cursor: pointer; }
</style>
</head>
<body>
<button class="trigger-btn" onclick="showToastV1()">Show Success Toast</button>
<div class="toast-container-v1" id="toast-container-v1"></div>
<script>
function showToastV1() {
const container = document.getElementById('toast-container-v1');
const toast = document.createElement('div');
toast.className = 'toast-v1 success';
toast.setAttribute('role', 'alert');
toast.innerHTML = `
<div class="toast-icon">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path><polyline points="22 4 12 14.01 9 11.01"></polyline></svg>
</div>
<div class="toast-content">
<h4 class="toast-title">Changes saved</h4>
<p class="toast-message">Your profile settings have been updated.</p>
</div>
<button class="toast-action">Undo</button>
<button class="toast-close" onclick="this.parentElement.remove()" aria-label="Close">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
</button>
`;
container.appendChild(toast);
// Auto remove
setTimeout(() => {
toast.style.animation = 'fadeOut 0.3s forwards';
toast.addEventListener('animationend', () => toast.remove());
}, 5000);
}
</script>
</body>
</html>
: "The Solid Signal" (High-Contrast & Functional)
<!DOCTYPE html>
<html lang="en">
<head>
<style>
:root {
--bg-surface: #121212;
--text-on-dark: #ffffff;
--text-muted-on-dark: #a1a1aa;
/* Solid Semantic Colors */
--solid-success: #064e3b;
--solid-success-border: #34d399;
--solid-error: #7f1d1d;
--solid-error-border: #f87171;
}
/* Shared reset for demo purposes */
body { margin: 0; }
/* Toast Container */
.toast-container-v2 {
position: fixed;
top: 24px;
right: 24px;
display: flex;
flex-direction: column;
gap: 16px;
z-index: 9999;
width: 360px;
max-width: 90vw;
}
/* The Toast Card */
.toast-v2 {
background: var(--bg-surface);
color: var(--text-on-dark);
border-radius: 4px;
padding: 0; /* Padding handled by grid */
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
display: grid;
grid-template-columns: auto 1fr auto;
align-items: center;
position: relative;
overflow: hidden;
animation: slideInRight 0.3s cubic-bezier(0.25, 1, 0.5, 1) forwards;
}
/* Variant: Error (Solid) */
.toast-v2.error {
background: var(--solid-error);
border-left: 1px solid var(--solid-error-border);
}
/* Icon Area */
.toast-v2-icon {
padding: 16px 0 16px 16px;
display: flex;
align-items: center;
color: var(--solid-error-border);
}
/* Content Area */
.toast-v2-content {
padding: 16px;
}
.toast-v2-title {
font-size: 14px;
font-weight: 700;
margin: 0 0 2px 0;
letter-spacing: 0.02em;
}
.toast-v2-msg {
font-size: 12px;
color: rgba(255,255,255,0.8);
margin: 0;
}
/* Close Button */
.toast-v2-close {
background: transparent;
border: none;
color: rgba(255,255,255,0.6);
cursor: pointer;
padding: 16px;
height: 100%;
transition: color 0.2s, background 0.2s;
}
.toast-v2-close:hover {
color: white;
background: rgba(255,255,255,0.1);
}
/* Progress Bar */
.toast-progress {
position: absolute;
bottom: 0;
left: 0;
height: 3px;
background: rgba(255,255,255,0.3);
width: 100%;
transform-origin: left;
animation: scaleX 4s linear forwards;
}
@keyframes slideInRight {
from { opacity: 0; transform: translateX(50px); }
to { opacity: 1; transform: translateX(0); }
}
@keyframes scaleX {
from { transform: scaleX(1); }
to { transform: scaleX(0); }
}
/* Demo Trigger */
.trigger-v2 { position: absolute; top: 50%; left: 50%; transform: translate(-50%, 50px); padding: 10px 20px; }
</style>
</head>
<body>
<button class="trigger-v2" onclick="showToastV2()">Show Error Toast</button>
<div class="toast-container-v2" id="toast-container-v2"></div>
<script>
function showToastV2() {
const container = document.getElementById('toast-container-v2');
const toast = document.createElement('div');
toast.className = 'toast-v2 error';
toast.setAttribute('role', 'alert');
toast.innerHTML = `
<div class="toast-v2-icon">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="8" x2="12" y2="12"></line><line x1="12" y1="16" x2="12.01" y2="16"></line></svg>
</div>
<div class="toast-v2-content">
<h4 class="toast-v2-title">Connection Failed</h4>
<p class="toast-v2-msg">Unable to sync data with server.</p>
</div>
<button class="toast-v2-close" onclick="this.parentElement.remove()" aria-label="Close">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
</button>
<div class="toast-progress"></div>
`;
container.appendChild(toast);
// Auto remove matches CSS animation time
setTimeout(() => {
toast.style.opacity = '0';
toast.style.transition = 'opacity 0.2s';
setTimeout(() => toast.remove(), 200);
}, 4000);
}
</script>
</body>
</html>