Context Display

Visualize token usage relative to a model's context window — ring, bar, or text — with a detailed hover popover.

Ring
Low (42%)
Warning (72%)
Critical (91%)
Bar
53.8k (42%)
92.2k (72%)
116.5k (91%)
Text
53.8k / 128.0k
92.2k / 128.0k
116.5k / 128.0k
On hover
Usage72%
Input72.3k
Cached41.2k
Output12.7k
Reasoning8.4k
Total92.2k / 128.0k

This component requires server-side setup to forward token usage metadata. Without it, ContextDisplay will show 0 usage and no breakdown data.

Getting Started

Add context-display

npx shadcn@latest add https://r.assistant-ui.com/context-display.json

This adds a /components/assistant-ui/context-display.tsx file to your project.

Forward token usage from your route handler

Use messageMetadata in your Next.js route to attach usage from finish and modelId from finish-step:

app/api/chat/route.ts
import { streamText, convertToModelMessages } from "ai";

export async function POST(req: Request) {
  const { messages, modelName } = await req.json();
  const result = streamText({
    model: getModel(modelName),
    messages: await convertToModelMessages(messages),
  });
  return result.toUIMessageStreamResponse({
    messageMetadata: ({ part }) => {
      if (part.type === "finish") {
        return {
          usage: part.totalUsage,
        };
      }
      if (part.type === "finish-step") {
        return {
          modelId: part.response.modelId,
        };
      }
      return undefined;
    },
  });
}

Use in your application

Pick a variant and place it in your thread footer, composer, or sidebar. Pass modelContextWindow with your model's token limit.

/components/assistant-ui/thread.tsx
import { ContextDisplay } from "@/components/assistant-ui/context-display";

const ThreadFooter: FC = () => {
  return (
    <div className="flex items-center justify-end px-3 py-1.5">
      <ContextDisplay.Bar modelContextWindow={128000} />
    </div>
  );
};

Variants

Three preset variants are available, each wrapping the shared tooltip popover:

// SVG donut ring (default, compact)
<ContextDisplay.Ring modelContextWindow={128000} />

// Horizontal progress bar with label
<ContextDisplay.Bar modelContextWindow={128000} />

// Minimal monospace text
<ContextDisplay.Text modelContextWindow={128000} />

All presets accept className for styling overrides and side to control tooltip placement ("top", "bottom", "left", "right").

Composable API

For custom visualizations, use the building blocks directly:

import { ContextDisplay } from "@/components/assistant-ui/context-display";

<ContextDisplay.Root modelContextWindow={128000}>
  <ContextDisplay.Trigger aria-label="Context usage">
    <MyCustomGauge />
  </ContextDisplay.Trigger>
  <ContextDisplay.Content side="top" />
</ContextDisplay.Root>
ComponentDescription
RootUses provided usage when supplied, otherwise fetches token usage internally; provides shared context and wraps children in a tooltip
TriggerButton that opens the tooltip on hover
ContentTooltip popover with the token breakdown (Usage %, Input, Cached, Output, Reasoning, Total)

API Reference

Preset Props

All preset variants (Ring, Bar, Text) share the same props:

PropTypeDefaultDescription
modelContextWindownumberMaximum token limit of the current model (required)
classNamestringAdditional class names on the trigger button
side"top" | "bottom" | "left" | "right""top"Tooltip placement
usageThreadTokenUsageOptional externally-provided usage data (skips internal usage fetch when provided)

Color Thresholds

Ring and Bar share the same severity colors:

LevelThresholdRingBar
Low< 65%stroke-emerald-500bg-emerald-500
Warning65% – 85%stroke-amber-500bg-amber-500
Critical> 85%stroke-red-500bg-red-500

Text displays numeric values only — no severity color.

  • Message Timing — Streaming performance stats (TTFT, tok/s)
  • Thread — The thread component where ContextDisplay is typically placed