Context Window
betaA meter for how much of a model's context window is used, like 84K of 200K tokens. It splits the use into parts with a legend, and turns warning near the limit.
Preview
parts
Context window
- System prompt: 4.2K
- Tools: 12.8K
- Files: 31K
- Chat: 36K
116K tokens left
actions
Context window
- System prompt: 4.2K
- schema.prisma: 9.4K
- billing.ts: 21.3K
- Chat: 118.6K
46.5K tokens left
limit
Context window
- System prompt: 4.2K
- Tools: 12.8K
- Files: 46.1K
- Chat: 112.5K
Context window
- System prompt: 4.2K
- Files: 61K
- Chat: 142.6K
tone
Context window (neutral)
44K tokens left
Context window (brand)
44K tokens left
Context window (danger)
44K tokens left
Context window (success)
44K tokens left
Context window (warning)
44K tokens left
size
Context window, sm
- System prompt: 4.2K
- Tools: 12.8K
- Files: 31K
- Chat: 36K
116K tokens left
Context window, md
- System prompt: 4.2K
- Tools: 12.8K
- Files: 31K
- Chat: 36K
116K tokens left
states
Loading
A new chat
- System prompt: 4.2K
195.8K tokens left
Warns earlier
- System prompt: 4.2K
- Tools: 12.8K
- Files: 46.1K
Install
1. Add the registry to
components.json, once per app. Without it, the shadcn CLI looks up@txbrendanin a public list that txbrendan/ui does not control.npx shadcn@latest registry add "@txbrendan=https://txbrendan.dev/r/{name}.json"2. Add the theme, once per app. It replaces your color tokens with ones checked for contrast.
npx shadcn@latest add @txbrendan/theme3. Add the component.
npx shadcn@latest add @txbrendan/context-window
Use it for
- Show what fills a model's context in a chat or agent product, beside the composer or in a session panel.
- Pass limit, the window's size in tokens, and parts in the order the bar shows them, like system prompt, tools, files, and chat.
- Keep to five parts. Each takes the next chart color. Group small ones into Other.
- It turns warning at 80% of the limit and danger once full. Pass warnAt to warn earlier, like 0.6.
- Pass action for the next step near the limit, like a Compact chat or New chat button.
- Give a part its own action to free up room, like { label: "Remove" } on a file or { label: "Compact", loading } on the chat. Pass the parts again with the new tokens, and the bar moves.
- Pass legend={false} and size="sm" for a small space.
Avoid it for
- A task that runs, like an upload. Use Progress.
- One plain share with no parts, like 72% of storage. Use Progress or Ring Progress.
- Billing or usage over a month, compared side by side. Use Breakdown List.
Props
- parts
Required. What fills the window, in the order the bar shows them. Five at most.
{ id?: string; label: string; tokens: number; action?: ContextWindowPartAction }[]
- ContextWindowPartAction
Type. A quiet button at the end of the part's legend row. Pass functions from a client component.
{ label: string; onClick?: () => void; loading?: boolean; disabled?: boolean }
- limit
Required. The window's size in tokens, like 200000.
number
- title
The card's title. It names the meter.
ReactNode · default "Context window"
- model
A small tag beside the title, like the model's name.
ReactNode
- warnAt
The share of the limit, from 0 to 1, where it turns warning. It turns danger once full.
number · default 0.8
- tone
Colors the percent and the last line. Left out, it is neutral, then warning from warnAt, then danger once full. Passed, it stays that tone.
"neutral" | "brand" | "danger" | "success" | "warning" · default "neutral"
- legend
Shows each part's name, tokens, and action under the bar.
boolean · default true
- action
A button in the last row, like Compact chat or New chat.
ReactNode
- loading
Shows placeholders while the numbers load.
boolean · default false
- size
Bar height and the number's size.
"sm" | "md" · default "md"
- locale
Formats the numbers the short way, like 84K.
string · default "en-US"
- className
Classes for the card. Later classes win.
string
| Prop | Type | Default | What it does |
|---|---|---|---|
| parts | { id?: string; label: string; tokens: number; action?: ContextWindowPartAction }[] | - | Required. What fills the window, in the order the bar shows them. Five at most. |
| ContextWindowPartAction | { label: string; onClick?: () => void; loading?: boolean; disabled?: boolean } | - | Type. A quiet button at the end of the part's legend row. Pass functions from a client component. |
| limit | number | - | Required. The window's size in tokens, like 200000. |
| title | ReactNode | "Context window" | The card's title. It names the meter. |
| model | ReactNode | - | A small tag beside the title, like the model's name. |
| warnAt | number | 0.8 | The share of the limit, from 0 to 1, where it turns warning. It turns danger once full. |
| tone | "neutral" | "brand" | "danger" | "success" | "warning" | "neutral" | Colors the percent and the last line. Left out, it is neutral, then warning from warnAt, then danger once full. Passed, it stays that tone. |
| legend | boolean | true | Shows each part's name, tokens, and action under the bar. |
| action | ReactNode | - | A button in the last row, like Compact chat or New chat. |
| loading | boolean | false | Shows placeholders while the numbers load. |
| size | "sm" | "md" | "md" | Bar height and the number's size. |
| locale | string | "en-US" | Formats the numbers the short way, like 84K. |
| className | string | - | Classes for the card. Later classes win. |
Accessibility
- The card is a group named by the title. The bar is a meter with the same name, and reads like "84K of 200K tokens used, 42%".
- The bar's colored parts are hidden from screen readers. The legend says each part's name and tokens in text.
- A part's action is named with the part, like "Remove Files", so each button says what it acts on.
- Near the limit, the last line says Almost full or Full in words, so the warning does not rest on color alone.
- In forced-colors mode the bar draws a border and its parts fill with the text color.
Examples
Split by part, under the limit
<ContextWindow
model="claude-opus-5-5"
limit={200000}
parts={[
{ label: "System prompt", tokens: 4200 },
{ label: "Tools", tokens: 12800 },
{ label: "Files", tokens: 31000 },
{ label: "Chat", tokens: 36000 },
]}
/>Near the limit, with a next step
import { Button } from "@/components/ui/button";
import { ContextWindow } from "@/components/ui/context-window";
export function SessionMeter() {
return (
<ContextWindow
limit={200000}
parts={[
{ label: "Files", tokens: 46100 },
{ label: "Chat", tokens: 129700 },
]}
action={
<Button size="sm" emphasis="outline">
Compact chat
</Button>
}
/>
);
}