Xzero UI
Pro library

Generation statsPro

A live stats strip for a streaming LLM response where time to first token, speed with a sparkline, output tokens and cost count up in tabular numerals beside the model's real mark, then settle and open into a latency and token cost breakdown.

$ pnpm dlx shadcn@4.23.0 add @xzero-ui-pro/generation-stats
Live · keyboard ready

When to use

When not to use

Installation

Register both Xzero UI namespaces in your project's components.json:

{
  "registries": {
    "@xzero-ui": "https://mcp.xzero.co.uk/r/{name}.json",
    "@xzero-ui-pro": "https://mcp.xzero.co.uk/r/pro/{name}.json"
  }
}
npx shadcn@4.23.0 add @xzero-ui-pro/generation-stats

Install xzero-foundation once, and import @/components/xzero/foundation.css in your app root. No Xzero token is used by this snapshot. For sample portraits, photos, fonts, or logos, download https://mcp.xzero.co.uk/install-assets.mjs and run node xzero-install-assets.mjs <receiving-project>.

Usage

import { GenerationStats } from "@/components/xzero/generation-stats/generation-stats";

// Under an assistant message, fed by your streaming handler.
export function MessageStats({ run }) {
  return (
    <GenerationStats
      variant="inline"
      model={{ name: "Claude Sonnet 5.5", provider: "anthropic", id: "claude-sonnet-5-5" }}
      status={run.status}                 // "waiting" | "streaming" | "done" | "stopped" | "error"
      startedAt={run.startedAt}           // Date.now() when the request went out
      usage={{
        inputTokens: run.usage.input_tokens + run.usage.cache_read_input_tokens,
        cachedTokens: run.usage.cache_read_input_tokens,
        outputTokens: run.outputTokens,   // update on every chunk
        ttftMs: run.ttftMs,               // set on the first token
        durationMs: run.durationMs,       // set on the last
      }}
      pricing={{ input: 3, cachedInput: 0.3, output: 15 }}
      error={run.error}
      onRetry={() => run.retry()}
    />
  );
}

// A dev panel card with the breakdown open.
<GenerationStats model={model} status="done" usage={usage} pricing={pricing} defaultExpanded />

// With no props it plays the sample runs.
<GenerationStats />

API reference

GenerationStats

A live stats strip for a streaming LLM response. The head shows the model's real mark, its name and a status with icon and label (Waiting, Streaming, Done in 4.18s, Stopped at 1.90s, Failed). Below it four cells split by hairlines: time to first token, speed in tokens per second with a small sparkline, output tokens and cost. While the response streams every number counts up in tabular numerals and the sparkline draws; when it ends the numbers settle on exact values. Details opens a breakdown with a latency bar (first token, generation, total) and a token table (input, cached input, output, reasoning, total) with rates and cost. A failed response gets a reason row with Retry. With no props it plays four sample runs (Claude Sonnet 5.5, GPT-6.1 Sol, Gemini 3.8 Flash and Mistral Large 4, which fails once and retries).

PropTypeDefaultDescription
status"idle" | "waiting" | "streaming" | "done" | "stopped" | "error"–Where the response is: waiting until the first token, streaming until the last. Leave it out to play the built in sample runs.
model{ name: string; provider: GenerationProvider; id?: string }–The model that answered. provider picks the mark: "anthropic", "openai", "google", "xai", "mistral", "deepseek", "meta" or "qwen". id goes into the copied JSON.
startedAtnumber–Epoch ms when the request was sent. While waiting, time to first token counts live from here; while streaming, total latency does.
usageGenerationUsage{}inputTokens (cached included), cachedTokens, outputTokens, reasoningTokens, ttftMs, durationMs, tokensPerSecond, costUsd. All optional. Update outputTokens as chunks arrive and set ttftMs on the first token and durationMs on the last; speed and cost are derived unless you pass tokensPerSecond or costUsd.
pricing{ input: number; cachedInput?: number; output: number }–USD per million tokens. Enables the Rate and Cost columns and the live cost. Reasoning tokens bill at the output rate; cachedInput defaults to the input rate.
speedSamplesnumber[]–Speed readings in tokens per second, oldest first, for the sparkline. By default the component reads speed every 160ms while outputTokens grows, smoothed, and keeps the whole run's shape.
errorstring–The reason shown in the error row when status is "error".
onRetry() => void–Shows Retry in the error row.
variant"card" | "inline""card"card is a bordered strip for dev panels and run views. inline is one quiet wrapping line ("412ms to first token · 88 tok/s · 284 tokens · $0.0077") for the space under a chat message; the breakdown opens as a panel below it.
expandedboolean–Controls the breakdown. Pair with onExpandedChange.
defaultExpandedbooleanfalseOpens the breakdown on first render when uncontrolled.
onExpandedChange(expanded: boolean) => void–Called when Details is pressed.
noteReactNode–A footnote under the breakdown, for example "Rates from your Anthropic contract, updated Oct 1, 2026". The preview uses it to say the run is simulated.
classNamestring–Class on the root element.

useGenerationSimulation

The simulated stream behind the preview, exported for prototypes and tests. Returns { frame, cueOpen, retry, next }, where frame holds model, pricing, status, startedAt, usage and error in exactly the shape GenerationStats takes. Output ramps up, wavers a few percent and arrives in chunks of four or more tokens, like a real stream. Nothing is sent anywhere.

PropTypeDefaultDescription
runsGenerationSampleRun[]generationSampleRunsThe runs to play in order. A run with failAtTokens fails there once and succeeds when retried.
activebooleantrueTicks only while true; pass false when the card is off screen.
holdbooleanfalseKeeps a settled run on screen instead of moving on.
loopbooleantruePlays the runs in a loop.

Keyboard interactions

KeysAction
TabMoves to Details, then Retry when a response failed, then the copy button inside an open breakdown.
Enter, SpaceOpens or closes the breakdown, retries, or copies the stats as JSON.

Accessibility

Motion

Responsive behavior

Performance

Notes for AI

Also in ai

Guidance for AI tools

Generation stats: A live stats strip for a streaming LLM response where time to first token, speed with a sparkline, output tokens and cost count up in tabular numerals beside the model's real mark, then settle and open into a latency and token cost breakdown. Follow the declared prop types and do not invent props. Keep keyboard access, reduced motion support, and both light and dark themes intact when adapting it.

Full library index: https://ui.xzero.co.uk/llms.txt

Browse all components