Elements

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>
  );
}