All Taste components
Cards & surfaces
Stacked notifications
A tidy pile of notifications that fans out into a readable list when you hover it.
stacked · fanned · drop-in entrance
Payment received$2,400 from Kaveri Foodsnow
Asha commented“Ship the new pricing on Monday?”4m
Deploy finishedtaste-web is live on production12m
"use client";
import { useState } from "react";
import { cn } from "@/lib/utils";
interface Note { id: string; title: string; text: string; time: string; icon: React.ReactNode }
export function NotificationStack({ notes }: { notes: Note[] }) {
const [open, setOpen] = useState(false);
const shown = notes.slice(0, 3);
return (
<div
onMouseEnter={() => setOpen(true)}
onMouseLeave={() => setOpen(false)}
onFocus={() => setOpen(true)}
onBlur={() => setOpen(false)}
className="relative w-full max-w-xs transition-[height] duration-500 ease-spring motion-reduce:transition-none"
style={{ height: open ? 70 + (shown.length - 1) * 72 : 92 }}
>
{shown.map((n, i) => (
<article
key={n.id}
tabIndex={0}
className="absolute inset-x-0 top-0 flex items-start gap-2.5 rounded-lg border border-border bg-bg px-3 py-2.5 text-[13px] shadow-md transition-transform duration-500 ease-spring animate-[stack-in_.6s_cubic-bezier(.2,.7,.1,1)_both] motion-reduce:animate-none motion-reduce:transition-none"
style={{
zIndex: shown.length - i,
transformOrigin: "50% 0",
transform: open ? "translateY(" + i * 72 + "px)" : "translateY(" + i * 10 + "px) scale(" + (1 - i * 0.05) + ")",
animationDelay: 100 + (shown.length - 1 - i) * 90 + "ms",
}}
>
<span className="grid size-[30px] flex-none place-items-center rounded-full bg-primary-soft text-primary-soft-fg">{n.icon}</span>
<span className={cn("min-w-0 flex-1 transition-opacity duration-300", !open && i > 0 && "opacity-0")}>
<b className="block font-medium text-fg">{n.title}</b>
<span className="block truncate text-fg-muted">{n.text}</span>
</span>
<span className={cn("whitespace-nowrap text-[11.5px] text-fg-subtle transition-opacity duration-300", !open && i > 0 && "opacity-0")}>{n.time}</span>
</article>
))}
</div>
);
}
/* globals.css
@keyframes stack-in { from { opacity: 0; translate: 0 -12px; } }
*/
The code uses the Taste Tailwind preset. Make yours on the Taste page with Export my system.