AI Chat Fancy Stable
ContextRing
How much of the context window is gone, in the space of a favicon: a donut that fills as the conversation grows, the compact count beside it, and an optional popover breaking the total down by what is holding it
Preview
svelte
<script lang="ts">
import { ContextRing } from "fancy-ui-svelte";
import type { TokenUsageData } from "fancy-ui-svelte";
// Nothing is on a timer here: every ring is a fixed reading and the popover
// only moves when you move it, so there is no rig to hold still for reduced
// motion and no effect in this file at all.
const comfortable: TokenUsageData = { used: 12_400, max: 200_000 };
const warning: TokenUsageData = { used: 164_000, max: 200_000 };
const critical: TokenUsageData = { used: 192_500, max: 200_000 };
const detailed: TokenUsageData = {
used: 84_300,
max: 200_000,
breakdown: [
{ label: "System prompt", tokens: 1850 },
{ label: "Transcript", tokens: 61_200 },
{ label: "Tool results", tokens: 18_400 },
{ label: "Attachments", tokens: 2850 },
],
};
</script>
<div class="flex w-full max-w-xl flex-col gap-6 p-6">
<div class="flex flex-wrap items-center gap-8">
<ContextRing usage={comfortable} />
<ContextRing usage={warning} />
<ContextRing usage={critical} />
</div>
<p class="text-muted-foreground text-xs">
The band shifts at 75% and again at 90%, using the same run-status colours as the rest of the AI
family. The arc's length says the same thing as its hue, so neither is load-bearing on its own.
</p>
<div class="border-border flex items-center gap-3 border-t pt-6">
<ContextRing usage={detailed} size={34} strokeWidth={4} expandable />
<span class="text-muted-foreground text-xs">
Press the ring for the breakdown. Escape closes it.
</span>
</div>
</div>Installation
pnpm add fancy-ui-svelte
import { ContextRing } from 'fancy-ui-svelte'
Usage
svelte
<script lang="ts">
import { ContextRing } from 'fancy-ui-svelte';
</script>
<ContextRing />Examples
Basic Usage
svelte
<script lang="ts">
import { ContextRing } from "$lib/fancy-ui/context-ring";
import type { TokenUsageData } from "$lib/fancy-ui/_internals/ai-types.js";
// Nothing is on a timer here: every ring is a fixed reading and the popover
// only moves when you move it, so there is no rig to hold still for reduced
// motion and no effect in this file at all.
const comfortable: TokenUsageData = { used: 12_400, max: 200_000 };
const warning: TokenUsageData = { used: 164_000, max: 200_000 };
const critical: TokenUsageData = { used: 192_500, max: 200_000 };
const detailed: TokenUsageData = {
used: 84_300,
max: 200_000,
breakdown: [
{ label: "System prompt", tokens: 1850 },
{ label: "Transcript", tokens: 61_200 },
{ label: "Tool results", tokens: 18_400 },
{ label: "Attachments", tokens: 2850 },
],
};
</script>
<div class="flex w-full max-w-xl flex-col gap-6 p-6">
<div class="flex flex-wrap items-center gap-8">
<ContextRing usage={comfortable} />
<ContextRing usage={warning} />
<ContextRing usage={critical} />
</div>
<p class="text-muted-foreground text-xs">
The band shifts at 75% and again at 90%, using the same run-status colours as the rest of the AI
family. The arc's length says the same thing as its hue, so neither is load-bearing on its own.
</p>
<div class="border-border flex items-center gap-3 border-t pt-6">
<ContextRing usage={detailed} size={34} strokeWidth={4} expandable />
<span class="text-muted-foreground text-xs">
Press the ring for the breakdown. Escape closes it.
</span>
</div>
</div>Props
| Prop | Type | Default | Description |
|---|---|---|---|
usage * | TokenUsageData | - | Context-window consumption: tokens used, out of how many, and optionally the breakdown rows the popover lists |
size | number | 28 | Outer diameter of the ring, in pixels; drives the viewBox and the radius |
strokeWidth | number | 3 | Thickness of the track and the arc, in pixels; clamped to the radius so a thick ring cannot eat its own centre |
showLabel | boolean | true | Whether the compact "12.4k / 200k" figure is shown beside the ring — exact under a thousand, one decimal under 100k, rounded above |
warnAt | number | 0.75 | Fraction at which the ring leaves the quiet band and takes the running colour |
criticalAt | number | 0.9 | Fraction at which the ring takes the error colour. Floored at warnAt, so a threshold set below the warning cannot create a band that never wins |
label | string | "Context usage" | Accessible name for the meter, and — when expandable — for the button that contains it |
expandable | boolean | false | Turns the ring into a button that toggles a popover listing usage.breakdown; closes on Escape, on a click outside, or on a second press |
Links
Related components
Ch
ChatError
Quiet inline failure banner for a chat turn: the error, an optional detail line, and a retry button that disables itself while the retry is in flight
AI Chat Stable
Ch
ChatMessage
One conversation turn, aligned and dressed by its role, streaming its body while the answer arrives, with an action rail that fades in on hover and a version navigator underneath
AI Chat Stable
Ch
ChatPanel
The shell a conversation lives in: a sticky header, a transcript that pins itself to the bottom while an answer arrives and offers the way back once you scroll up, and a sticky composer row
AI Chat Stable