Notification row with an unread dot, title, body and timestamp.
Draft published
Your changelog is live on the preview URL.
New comment
Maya left a note on the pricing section.
Theme synced
Dark tokens were updated.
npx @agents-npm-packages/vibeui add notification --dir ./src/components/uiImport
import { NotificationItem } from "@/components/ui/notification"Generated from the component's TypeScript types, so it always matches the source. * marks a required prop.
| Prop | Type | Default | Description |
|---|---|---|---|
| title* | string | — | Heading text. |
| body* | string | — | Message text. |
| time* | string | — | Timestamp label, e.g. “2m”. |
| unread | boolean | — | Shows an animated unread dot. |
| className | string | — | Extra classes, merged with the component's own. |
import { cn } from "@/lib/utils";
/** Notification row with an unread dot, title, body and timestamp. */
export function NotificationItem({
title,
body,
time,
unread,
className,
}: {
title: string;
body: string;
time: string;
unread?: boolean;
className?: string;
}) {
return (
<div
className={cn(
"flex animate-fade-up gap-3 rounded-md px-3 py-3 transition-[background-color,transform] duration-200 hover:translate-x-0.5 hover:bg-surface-muted/70",
className,
)}
>
<span
aria-label={unread ? "Unread" : undefined}
className="relative mt-[7px] flex size-2 shrink-0"
>
{unread ? (
<span className="absolute inset-0 animate-ping-soft rounded-full bg-accent opacity-50" />
) : null}
<span
className={cn(
"relative size-2 rounded-full transition-colors duration-300",
unread ? "bg-accent" : "bg-line-strong",
)}
/>
</span>
<div className="min-w-0 flex-1">
<div className="flex items-baseline justify-between gap-2">
<p className="truncate text-sm font-medium text-ink">{title}</p>
<time className="shrink-0 text-[11px] text-faint">{time}</time>
</div>
<p className="mt-0.5 line-clamp-2 text-[13px] leading-relaxed text-muted">
{body}
</p>
</div>
</div>
);
}
Exports NotificationItem. Peer dependencies: clsx, tailwind-merge.