20 / 122 · Messages
Timestamps
Chronology in a long thread: days marked, times on hover.
Yesterday
Why does the draft survive a reload?16:04
It's persisted per thread, so the slot is read back on mount.16:04
Today
And across thread switches?09:12
Each thread owns its own slot, so nothing leaks between them.09:12
Installation
npx shadcn@latest add "@assistant-ui/elements-day-separator"
Usage
import { DaySeparator } from "@/components/elements/day-separator";
<DaySeparator messages={messages} />Props
DaySeparator
messages*DatedMessage[]Turns in order. A separator is inserted wherever day changes from the previous message, so grouping needs no pre-processing.
classNamestringExtra classes merged onto the root.
DatedMessage
id*stringStable identity for the row key.
role*"user" | "assistant"Who sent it. User turns sit right in a bubble, assistant turns run flush left.
text*stringMessage body.
day*stringPre-formatted day label. Compared against the previous message to decide where a rule goes.
time*stringPre-formatted time, revealed on hover.
Source
day-separator.tsx"use client";
import { cn } from "@/lib/utils";
import { mono } from "./surfaces";
export interface DatedMessage {
id: string;
day: string;
time: string;
role: "user" | "assistant";
text: string;
}
export function DaySeparator({
messages,
className,
}: {
messages: readonly DatedMessage[];
className?: string;
}) {
let lastDay = "";
return (
<div className={cn("flex w-full max-w-sm flex-col gap-2", className)}>
{messages.map((message) => {
const newDay = message.day !== lastDay;
lastDay = message.day;
return (
<div key={message.id} className="flex flex-col gap-2">
{newDay && (
<div className="flex items-center gap-2.5 py-1">
<span className="bg-foreground/[0.08] h-px flex-1" />
<span className={cn(mono, "text-foreground/30")}>
{message.day}
</span>
<span className="bg-foreground/[0.08] h-px flex-1" />
</div>
)}
<div
className={cn(
"group flex items-baseline gap-2",
message.role === "user" && "flex-row-reverse",
)}
>
<span
className={cn(
"max-w-[80%] text-[13.5px] leading-relaxed",
message.role === "user"
? "bg-foreground/[0.05] rounded-2xl px-3.5 py-2"
: "text-foreground/75",
)}
>
{message.text}
</span>
<span
className={cn(
mono,
"text-foreground/0 group-hover:text-foreground/30 shrink-0 tabular-nums transition-colors",
)}
>
{message.time}
</span>
</div>
</div>
);
})}
</div>
);
}