19 / 122 · Messages
Timing footer
What the turn cost: time to first token, throughput, tokens, money.
ttft0.4selapsed0.0stok/s58
Installation
npx shadcn@latest add "@assistant-ui/elements-message-timing"
Usage
import { MessageTiming } from "@/components/elements/message-timing";
<MessageTiming
stats={[
{ label: "ttft", value: "0.4s" },
{ label: "total", value: "2.6s" },
]}
/>Props
stats*TimingStat[]Label and value pairs, pre-formatted. Show fewer while streaming and the full set once the turn settles.
streamingbooleanTints the values blue while they are still moving.
classNamestringExtra classes merged onto the root.
Source
message-timing.tsx"use client";
import { cn } from "@/lib/utils";
import { mono } from "./surfaces";
export interface TimingStat {
label: string;
value: string;
}
export function MessageTiming({
stats,
streaming,
className,
}: {
stats: readonly TimingStat[];
streaming?: boolean;
className?: string;
}) {
return (
<div
className={cn(
"fade-in animate-in flex w-full max-w-sm flex-wrap items-center gap-x-3 gap-y-1 duration-500",
className,
)}
>
{stats.map((stat) => (
<span key={stat.label} className="flex items-baseline gap-1">
<span className={cn(mono, "text-foreground/25")}>{stat.label}</span>
<span
className={cn(
mono,
"tabular-nums",
streaming
? "text-blue-500 dark:text-blue-400"
: "text-foreground/50",
)}
>
{stat.value}
</span>
</span>
))}
</div>
);
}