Skip to content
AI Interfaces block

Context Window Budget

What is in the context and what fell out of it — a stacked budget with the reply reserve drawn as a segment, and the dropped chunks named with the reason, which is the part nobody ships.

309 lineslucide-reactAdded 27 Aug 2026Updated 10 Sept 2026
  • context
  • retrieval
  • tokens
  • budget
  • rag

What's included

  • components/context-window-budget.tsx
  • Needs lucide-react

Works with

  • React
  • Next.js
  • Tailwind CSS
  • TypeScript

npx hoverlab add context-window-budget

Or over MCP, from your editor's agent — no account needed.

License

Free to read, copy and install, for personal and non-commercial projects. Shipping it in client work or a paid product needs Pro ($79 once). The source lands in your repo and stops being ours — no attribution, nothing to upgrade.

Was this useful?

Start a page with this section — add more, order them, and leave with the page source.

Preview

Context for this reply

27.0k of 32.0k tokens · 84%

  • System promptAgent role and house rules1.4k4%
  • Tool definitions9 tools, JSON schema3.1k10%
  • ConversationLast 14 turns8.2k26%
  • refunds-policy.mdWhole file · pinned by you4.8k15%
  • Q3-support-metrics.csvRows 1–200 of 4,8124.4k14%
  • escalation-runbook.md3 of 9 sections, ranked by the query2.9k9%
  • Held for the replyRoom the answer needs2.2k7%

Left out to make it fit

The model did not see any of this. If an answer looks like it ignored a document, start here.

  • Q3-support-metrics.csv — rows 201–4,812Too large for the window. Only the first 200 rows were sent.96.0k
  • contract-meridian-2024.pdfRanked 8th; seven chunks fitted. Pin it to force it in.18.3k
  • Conversation turns 1–6Aged out of the rolling history window.7.1k

Rendered live in your current theme — this is the same component whose source is below, not a screenshot of it.

Source

components/context-window-budget.tsx
'use client'

/**
 * <ContextWindowBudget> — what is in the context, and what fell out of it.
 *
 * Retrieval & Context had the source picker, the chunk cards, the citation
 * list and the empty state: four views of what the model *used*. None of
 * them can answer the question people actually ask when an answer is
 * wrong — "did it even see the file?" This is that view.
 *
 * THE ONE THING THIS GETS RIGHT THAT MOST DO NOT
 *
 * The dropped items are on screen, with the reason. Every retrieval
 * pipeline evicts something: a chunk that ranked eighth when only seven
 * fit, a conversation turn that aged out, a 4MB PDF nothing was ever going
 * to fit whole. Products show the seven and stay silent about the eighth,
 * so the failure looks like the model ignoring a document rather than the
 * document never arriving. Naming the eighth turns an unfalsifiable
 * complaint into a fixable one — and the fix is usually "pin it", which is
 * a control here.
 *
 * THE RESERVE IS DRAWN AS PART OF THE BAR
 *
 * A context that is 100% full cannot reply. The room held back for the
 * answer is a segment like any other, not headroom left over at the end,
 * because it is the segment that gets eaten first when somebody pins four
 * more files and then wonders why replies got shorter.
 *
 * PERCENTAGES AND TOKENS, BOTH
 *
 * Tokens are the unit that runs out and the one the bill is in; per cent
 * is the only unit anybody can read off a bar. Showing one without the
 * other means either a number nobody can place or a proportion nobody can
 * act on.
 *
 * ACCESSIBILITY: the bar is a `role="img"` with an `aria-label` carrying
 * the whole breakdown in words — a screen-reader user gets the summary in
 * one string instead of a dozen unlabelled divs, and the same numbers are
 * in the legend below for anyone reading it as a list. Pin buttons are
 * `aria-pressed` toggles, so their state is real rather than implied by a
 * filled icon.
 */

import * as React from 'react'
import {
  AlertTriangle,
  CornerDownLeft,
  FileText,
  MessagesSquare,
  Pin,
  Settings2,
  Wrench,
} from 'lucide-react'

export type SegmentKind = 'system' | 'tools' | 'history' | 'retrieved' | 'reserve'

export interface ContextItem {
  id: string
  label: string
  detail: string
  tokens: number
  kind: SegmentKind
  pinned?: boolean
}

export interface DroppedItem {
  label: string
  tokens: number
  /** Why it did not make it in. Never omitted — it is the whole point. */
  reason: string
}

export interface ContextWindowBudgetProps {
  windowTokens?: number
  reserveTokens?: number
  items?: ContextItem[]
  dropped?: DroppedItem[]
  className?: string
}

const DEFAULT_ITEMS: ContextItem[] = [
  { id: 'sys', label: 'System prompt', detail: 'Agent role and house rules', tokens: 1_400, kind: 'system' },
  { id: 'tools', label: 'Tool definitions', detail: '9 tools, JSON schema', tokens: 3_100, kind: 'tools' },
  { id: 'hist', label: 'Conversation', detail: 'Last 14 turns', tokens: 8_200, kind: 'history' },
  {
    id: 'doc-1',
    label: 'refunds-policy.md',
    detail: 'Whole file · pinned by you',
    tokens: 4_800,
    kind: 'retrieved',
    pinned: true,
  },
  {
    id: 'doc-2',
    label: 'Q3-support-metrics.csv',
    detail: 'Rows 1–200 of 4,812',
    tokens: 4_400,
    kind: 'retrieved',
  },
  {
    id: 'doc-3',
    label: 'escalation-runbook.md',
    detail: '3 of 9 sections, ranked by the query',
    tokens: 2_900,
    kind: 'retrieved',
  },
]

const DEFAULT_DROPPED: DroppedItem[] = [
  {
    label: 'Q3-support-metrics.csv — rows 201–4,812',
    tokens: 96_000,
    reason: 'Too large for the window. Only the first 200 rows were sent.',
  },
  {
    label: 'contract-meridian-2024.pdf',
    tokens: 18_300,
    reason: 'Ranked 8th; seven chunks fitted. Pin it to force it in.',
  },
  {
    label: 'Conversation turns 1–6',
    tokens: 7_100,
    reason: 'Aged out of the rolling history window.',
  },
]

const KIND_LABEL: Record<SegmentKind, string> = {
  system: 'System',
  tools: 'Tools',
  history: 'Conversation',
  retrieved: 'Retrieved',
  reserve: 'Held for the reply',
}

const KIND_ICON: Record<SegmentKind, React.ComponentType<{ className?: string }>> = {
  system: Settings2,
  tools: Wrench,
  history: MessagesSquare,
  retrieved: FileText,
  reserve: CornerDownLeft,
}

/*
  The catalog's series ramp: color-mix in oklab, walking each step toward
  the card colour. These tokens are oklch(), so hsl(var(--primary)) is not
  a colour at all — the declaration is dropped and the segment renders
  invisible against the track.
*/
function rampColor(step: number, steps: number) {
  const toward = steps <= 1 ? 0 : (step / (steps - 1)) * 78
  return `color-mix(in oklab, var(--primary) ${100 - toward}%, var(--card))`
}

function compact(tokens: number) {
  return tokens >= 1000 ? `${(tokens / 1000).toFixed(1)}k` : String(tokens)
}

export function ContextWindowBudget({
  windowTokens = 32_000,
  reserveTokens = 2_200,
  items = DEFAULT_ITEMS,
  dropped = DEFAULT_DROPPED,
  className = '',
}: ContextWindowBudgetProps) {
  const [pinned, setPinned] = React.useState<string[]>(
    items.filter((i) => i.pinned).map((i) => i.id),
  )

  const used = items.reduce((sum, i) => sum + i.tokens, 0)
  /* Drawn as a segment, not as leftover space — see the note above. */
  const segments = [
    ...items,
    {
      id: 'reserve',
      label: KIND_LABEL.reserve,
      detail: 'Room the answer needs',
      tokens: reserveTokens,
      kind: 'reserve' as SegmentKind,
    },
  ]
  const committed = used + reserveTokens
  const free = Math.max(0, windowTokens - committed)
  const pct = (t: number) => (t / windowTokens) * 100

  const summary = `${compact(committed)} of ${compact(windowTokens)} tokens committed: ${segments
    .map((s) => `${s.label} ${Math.round(pct(s.tokens))}%`)
    .join(', ')}. ${compact(free)} free.`

  return (
    <section className={`mx-auto w-full max-w-2xl px-4 py-16 sm:px-6 ${className}`}>
      <div className="rounded-2xl border border-border bg-card p-5">
        <header className="flex flex-wrap items-baseline gap-x-3 gap-y-1">
          <h2 className="text-base font-semibold text-foreground">Context for this reply</h2>
          <p className="text-sm text-muted-foreground">
            {/* The unit that runs out, and the unit anyone can read. */}
            <span className="tabular-nums text-foreground">{compact(committed)}</span> of{' '}
            <span className="tabular-nums">{compact(windowTokens)}</span> tokens ·{' '}
            <span className="tabular-nums">{Math.round(pct(committed))}%</span>
          </p>
        </header>

        {/* One label carrying the whole breakdown, rather than a dozen divs. */}
        <div
          role="img"
          aria-label={summary}
          className="mt-4 flex h-3 w-full gap-0.5 overflow-hidden rounded-full border border-transparent bg-muted"
        >
          {segments.map((seg, i) => (
            <div
              key={seg.id}
              style={{
                width: `${pct(seg.tokens)}%`,
                background:
                  seg.kind === 'reserve'
                    ? 'color-mix(in oklab, var(--muted-foreground) 45%, var(--card))'
                    : rampColor(i, segments.length - 1),
              }}
              className="h-full border border-transparent first:rounded-s-full"
            />
          ))}
        </div>

        <ul className="mt-4 space-y-2">
          {segments.map((seg, i) => {
            const Icon = KIND_ICON[seg.kind]
            const isPinned = pinned.includes(seg.id)
            const canPin = seg.kind === 'retrieved'
            return (
              <li key={seg.id} className="flex items-center gap-3">
                <span
                  aria-hidden
                  style={{
                    background:
                      seg.kind === 'reserve'
                        ? 'color-mix(in oklab, var(--muted-foreground) 45%, var(--card))'
                        : rampColor(i, segments.length - 1),
                  }}
                  className="h-2.5 w-2.5 shrink-0 rounded-sm border border-transparent"
                />
                <Icon aria-hidden className="h-3.5 w-3.5 shrink-0 text-muted-foreground" />
                <span className="min-w-0 flex-1">
                  <span className="block truncate text-sm text-foreground">{seg.label}</span>
                  <span className="block truncate text-xs text-muted-foreground">
                    {seg.detail}
                  </span>
                </span>
                <span className="shrink-0 text-end text-xs tabular-nums text-muted-foreground">
                  {compact(seg.tokens)}
                  <span className="ms-1.5 text-foreground">{Math.round(pct(seg.tokens))}%</span>
                </span>
                {canPin ? (
                  <button
                    type="button"
                    aria-pressed={isPinned}
                    onClick={() =>
                      setPinned((p) =>
                        p.includes(seg.id) ? p.filter((x) => x !== seg.id) : [...p, seg.id],
                      )
                    }
                    className={`inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-lg transition hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background ${
                      isPinned ? 'text-primary' : 'text-muted-foreground'
                    }`}
                  >
                    <Pin aria-hidden className="h-3.5 w-3.5" />
                    <span className="sr-only">
                      {isPinned ? 'Unpin' : 'Pin'} {seg.label}
                    </span>
                  </button>
                ) : (
                  <span className="h-7 w-7 shrink-0" />
                )}
              </li>
            )
          })}
        </ul>

        {/* The part nobody ships. */}
        {dropped.length > 0 ? (
          <div className="mt-5 rounded-xl border border-border bg-muted/40 p-4">
            <h3 className="flex items-center gap-2 text-sm font-semibold text-foreground">
              <AlertTriangle aria-hidden className="h-4 w-4 text-amber-600 dark:text-amber-400" />
              Left out to make it fit
            </h3>
            <p className="mt-1 text-xs text-muted-foreground">
              The model did not see any of this. If an answer looks like it
              ignored a document, start here.
            </p>
            <ul className="mt-3 space-y-2">
              {dropped.map((d) => (
                <li key={d.label} className="flex gap-3 text-xs">
                  <span className="min-w-0 flex-1">
                    <span className="block truncate font-medium text-foreground">
                      {d.label}
                    </span>
                    <span className="block text-muted-foreground">{d.reason}</span>
                  </span>
                  <span className="shrink-0 tabular-nums text-muted-foreground">
                    {compact(d.tokens)}
                  </span>
                </li>
              ))}
            </ul>
          </div>
        ) : null}
      </div>
    </section>
  )
}

Before you paste

  • Styling is Tailwind utility classes on semantic tokens (bg-card, text-muted-foreground) — it inherits your theme instead of overriding it.
  • Install: npm i lucide-react
  • Every prop has a default, so it renders standalone before you wire it up.

Where it goes

Drop it at components/context-window-budget.tsx and import it where you need the section:

import { ContextWindowBudget } from '@/components/context-window-budget'

Props

Read out of the component’s own type and signature, so this cannot drift from the source below. Every prop has a default — the component renders standalone before you pass it anything.

PropTypeDefault
windowTokensnumber32_000
reserveTokensnumber2_200
itemsContextItem[]DEFAULT_ITEMS
droppedDroppedItem[]DEFAULT_DROPPED
classNamestring''

Not using React?

The same block rendered once to markup, wrapped as a file your framework compiles. Tailwind classes are framework-agnostic, so the design transfers intact — the behaviour does not.

This block is interactive. The markup below is its initial state with the event handlers stripped — you will need to re-wire the behaviour in your framework.

context-window-budget.html
<!--
  Context Window Budget — markup from the Hoverlab catalog.

  This is the block rendered once to HTML and wrapped as a component
  file. It is not a port of the React source: the Tailwind classes carry
  the design, which is the part that took the work, and they are the same
  in every framework.

  This block is interactive in React and the handlers are NOT here.
  Buttons, toggles and menus render in their initial state and do
  nothing until you wire them up.
-->
<section class="mx-auto w-full max-w-2xl px-4 py-16 sm:px-6 ">
  <div class="rounded-2xl border border-border bg-card p-5">
    <header class="flex flex-wrap items-baseline gap-x-3 gap-y-1">
      <h2 class="text-base font-semibold text-foreground">Context for this reply</h2>
      <p class="text-sm text-muted-foreground"><span class="tabular-nums text-foreground">27.0k</span> of <span class="tabular-nums">32.0k</span> tokens · <span class="tabular-nums">84%</span></p>
    </header>
    <div role="img" aria-label="27.0k of 32.0k tokens committed: System prompt 4%, Tool definitions 10%, Conversation 26%, refunds-policy.md 15%, Q3-support-metrics.csv 14%, escalation-runbook.md 9%, Held for the reply 7%. 5.0k free." class="mt-4 flex h-3 w-full gap-0.5 overflow-hidden rounded-full border border-transparent bg-muted">
      <div style="width:4.375%;background:color-mix(in oklab, var(--primary) 100%, var(--card))" class="h-full border border-transparent first:rounded-s-full"></div>
      <div style="width:9.6875%;background:color-mix(in oklab, var(--primary) 84.4%, var(--card))" class="h-full border border-transparent first:rounded-s-full"></div>
      <div style="width:25.624999999999996%;background:color-mix(in oklab, var(--primary) 68.8%, var(--card))" class="h-full border border-transparent first:rounded-s-full"></div>
      <div style="width:15%;background:color-mix(in oklab, var(--primary) 53.2%, var(--card))" class="h-full border border-transparent first:rounded-s-full"></div>
      <div style="width:13.750000000000002%;background:color-mix(in oklab, var(--primary) 37.599999999999994%, var(--card))" class="h-full border border-transparent first:rounded-s-full"></div>
      <div style="width:9.0625%;background:color-mix(in oklab, var(--primary) 22%, var(--card))" class="h-full border border-transparent first:rounded-s-full"></div>
      <div style="width:6.875000000000001%;background:color-mix(in oklab, var(--muted-foreground) 45%, var(--card))" class="h-full border border-transparent first:rounded-s-full"></div>
    </div>
    <ul class="mt-4 space-y-2">
      <li class="flex items-center gap-3">
        <span aria-hidden="true" style="background:color-mix(in oklab, var(--primary) 100%, var(--card))" class="h-2.5 w-2.5 shrink-0 rounded-sm border border-transparent"></span>
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-settings2 lucide-settings-2 h-3.5 w-3.5 shrink-0 text-muted-foreground" aria-hidden="true">
          <path d="M14 17H5"></path>
          <path d="M19 7h-9"></path>
          <circle cx="17" cy="17" r="3"></circle>
          <circle cx="7" cy="7" r="3"></circle>
        </svg>
        <span class="min-w-0 flex-1">
          <span class="block truncate text-sm text-foreground">System prompt</span>
          <span class="block truncate text-xs text-muted-foreground">Agent role and house rules</span>
        </span>
        <span class="shrink-0 text-end text-xs tabular-nums text-muted-foreground">1.4k<span class="ms-1.5 text-foreground">4%</span></span>
        <span class="h-7 w-7 shrink-0"></span>
      </li>
      <li class="flex items-center gap-3">
        <span aria-hidden="true" style="background:color-mix(in oklab, var(--primary) 84.4%, var(--card))" class="h-2.5 w-2.5 shrink-0 rounded-sm border border-transparent"></span>
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-wrench h-3.5 w-3.5 shrink-0 text-muted-foreground" aria-hidden="true">
          <path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"></path>
        </svg>
        <span class="min-w-0 flex-1">
          <span class="block truncate text-sm text-foreground">Tool definitions</span>
          <span class="block truncate text-xs text-muted-foreground">9 tools, JSON schema</span>
        </span>
        <span class="shrink-0 text-end text-xs tabular-nums text-muted-foreground">3.1k<span class="ms-1.5 text-foreground">10%</span></span>
        <span class="h-7 w-7 shrink-0"></span>
      </li>
      <li class="flex items-center gap-3">
        <span aria-hidden="true" style="background:color-mix(in oklab, var(--primary) 68.8%, var(--card))" class="h-2.5 w-2.5 shrink-0 rounded-sm border border-transparent"></span>
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-messages-square h-3.5 w-3.5 shrink-0 text-muted-foreground" aria-hidden="true">
          <path d="M14 9a2 2 0 0 1-2 2H6l-4 4V4a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2z"></path>
          <path d="M18 9h2a2 2 0 0 1 2 2v11l-4-4h-6a2 2 0 0 1-2-2v-1"></path>
        </svg>
        <span class="min-w-0 flex-1">
          <span class="block truncate text-sm text-foreground">Conversation</span>
          <span class="block truncate text-xs text-muted-foreground">Last 14 turns</span>
        </span>
        <span class="shrink-0 text-end text-xs tabular-nums text-muted-foreground">8.2k<span class="ms-1.5 text-foreground">26%</span></span>
        <span class="h-7 w-7 shrink-0"></span>
      </li>
      <li class="flex items-center gap-3">
        <span aria-hidden="true" style="background:color-mix(in oklab, var(--primary) 53.2%, var(--card))" class="h-2.5 w-2.5 shrink-0 rounded-sm border border-transparent"></span>
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-file-text h-3.5 w-3.5 shrink-0 text-muted-foreground" aria-hidden="true">
          <path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"></path>
          <path d="M14 2v4a2 2 0 0 0 2 2h4"></path>
          <path d="M10 9H8"></path>
          <path d="M16 13H8"></path>
          <path d="M16 17H8"></path>
        </svg>
        <span class="min-w-0 flex-1">
          <span class="block truncate text-sm text-foreground">refunds-policy.md</span>
          <span class="block truncate text-xs text-muted-foreground">Whole file · pinned by you</span>
        </span>
        <span class="shrink-0 text-end text-xs tabular-nums text-muted-foreground">4.8k<span class="ms-1.5 text-foreground">15%</span></span>
        <button type="button" aria-pressed="true" class="inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-lg transition hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background text-primary">
          <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-pin h-3.5 w-3.5" aria-hidden="true">
            <path d="M12 17v5"></path>
            <path d="M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z"></path>
          </svg>
          <span class="sr-only">Unpin refunds-policy.md</span>
        </button>
      </li>
      <li class="flex items-center gap-3">
        <span aria-hidden="true" style="background:color-mix(in oklab, var(--primary) 37.599999999999994%, var(--card))" class="h-2.5 w-2.5 shrink-0 rounded-sm border border-transparent"></span>
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-file-text h-3.5 w-3.5 shrink-0 text-muted-foreground" aria-hidden="true">
          <path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"></path>
          <path d="M14 2v4a2 2 0 0 0 2 2h4"></path>
          <path d="M10 9H8"></path>
          <path d="M16 13H8"></path>
          <path d="M16 17H8"></path>
        </svg>
        <span class="min-w-0 flex-1">
          <span class="block truncate text-sm text-foreground">Q3-support-metrics.csv</span>
          <span class="block truncate text-xs text-muted-foreground">Rows 1–200 of 4,812</span>
        </span>
        <span class="shrink-0 text-end text-xs tabular-nums text-muted-foreground">4.4k<span class="ms-1.5 text-foreground">14%</span></span>
        <button type="button" aria-pressed="false" class="inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-lg transition hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background text-muted-foreground">
          <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-pin h-3.5 w-3.5" aria-hidden="true">
            <path d="M12 17v5"></path>
            <path d="M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z"></path>
          </svg>
          <span class="sr-only">Pin Q3-support-metrics.csv</span>
        </button>
      </li>
      <li class="flex items-center gap-3">
        <span aria-hidden="true" style="background:color-mix(in oklab, var(--primary) 22%, var(--card))" class="h-2.5 w-2.5 shrink-0 rounded-sm border border-transparent"></span>
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-file-text h-3.5 w-3.5 shrink-0 text-muted-foreground" aria-hidden="true">
          <path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"></path>
          <path d="M14 2v4a2 2 0 0 0 2 2h4"></path>
          <path d="M10 9H8"></path>
          <path d="M16 13H8"></path>
          <path d="M16 17H8"></path>
        </svg>
        <span class="min-w-0 flex-1">
          <span class="block truncate text-sm text-foreground">escalation-runbook.md</span>
          <span class="block truncate text-xs text-muted-foreground">3 of 9 sections, ranked by the query</span>
        </span>
        <span class="shrink-0 text-end text-xs tabular-nums text-muted-foreground">2.9k<span class="ms-1.5 text-foreground">9%</span></span>
        <button type="button" aria-pressed="false" class="inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-lg transition hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background text-muted-foreground">
          <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-pin h-3.5 w-3.5" aria-hidden="true">
            <path d="M12 17v5"></path>
            <path d="M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z"></path>
          </svg>
          <span class="sr-only">Pin escalation-runbook.md</span>
        </button>
      </li>
      <li class="flex items-center gap-3">
        <span aria-hidden="true" style="background:color-mix(in oklab, var(--muted-foreground) 45%, var(--card))" class="h-2.5 w-2.5 shrink-0 rounded-sm border border-transparent"></span>
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-corner-down-left h-3.5 w-3.5 shrink-0 text-muted-foreground" aria-hidden="true">
          <path d="M20 4v7a4 4 0 0 1-4 4H4"></path>
          <path d="m9 10-5 5 5 5"></path>
        </svg>
        <span class="min-w-0 flex-1">
          <span class="block truncate text-sm text-foreground">Held for the reply</span>
          <span class="block truncate text-xs text-muted-foreground">Room the answer needs</span>
        </span>
        <span class="shrink-0 text-end text-xs tabular-nums text-muted-foreground">2.2k<span class="ms-1.5 text-foreground">7%</span></span>
        <span class="h-7 w-7 shrink-0"></span>
      </li>
    </ul>
    <div class="mt-5 rounded-xl border border-border bg-muted/40 p-4">
      <h3 class="flex items-center gap-2 text-sm font-semibold text-foreground"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-triangle-alert h-4 w-4 text-amber-600 dark:text-amber-400" aria-hidden="true"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"></path><path d="M12 9v4"></path><path d="M12 17h.01"></path></svg>Left out to make it fit</h3>
      <p class="mt-1 text-xs text-muted-foreground">The model did not see any of this. If an answer looks like it ignored a document, start here.</p>
      <ul class="mt-3 space-y-2">
        <li class="flex gap-3 text-xs">
          <span class="min-w-0 flex-1">
            <span class="block truncate font-medium text-foreground">Q3-support-metrics.csv — rows 201–4,812</span>
            <span class="block text-muted-foreground">Too large for the window. Only the first 200 rows were sent.</span>
          </span>
          <span class="shrink-0 tabular-nums text-muted-foreground">96.0k</span>
        </li>
        <li class="flex gap-3 text-xs">
          <span class="min-w-0 flex-1">
            <span class="block truncate font-medium text-foreground">contract-meridian-2024.pdf</span>
            <span class="block text-muted-foreground">Ranked 8th; seven chunks fitted. Pin it to force it in.</span>
          </span>
          <span class="shrink-0 tabular-nums text-muted-foreground">18.3k</span>
        </li>
        <li class="flex gap-3 text-xs">
          <span class="min-w-0 flex-1">
            <span class="block truncate font-medium text-foreground">Conversation turns 1–6</span>
            <span class="block text-muted-foreground">Aged out of the rolling history window.</span>
          </span>
          <span class="shrink-0 tabular-nums text-muted-foreground">7.1k</span>
        </li>
      </ul>
    </div>
  </div>
</section>
  • This is rendered HTML, not a translation of the React source. The Tailwind classes carry the design and work in any framework.
  • It is one frame: the component in its initial state, with no props applied beyond the defaults.
  • This block is interactive in React — toggles, menus or form state. None of that survives here; the markup is the closed/default state and the handlers are gone. Re-wire them in your own framework.
  • Requires Tailwind, and the design tokens the classes reference (bg-card, text-muted-foreground, and so on). The template ZIPs ship a globals.css that defines them.

What each framework gets across the whole catalog — effects convert properly; this rung is markup.

For AI

The component, its props, the design tokens it expects and the command that installs it — as one prompt. Paste it into Claude, Cursor, v0 or ChatGPT and what they build around it will match the rest of the catalog instead of inventing its own system.

See the prompt

Used in these pages

Want the whole screen instead of this one section? Open a page and copy it entire.

8 more blocks in Retrieval & Context

All of them free to read, copy and install — no account, no locked tiles, no watermarked preview. The whole catalog is open, and so are the API and the CLI.

Browse Retrieval & Context

Shipping one commercially

Copying the code is free. Putting it in client work or a paid product is what Pro is for — the licence, not the access.

  • A commercial licence for everything in the catalog
  • Unlimited bundle exports, in Vue, Svelte and Tailwind
  • One payment — no subscription, nothing to renew
Pro — $79 once

More Retrieval & Context blocks

View category
Open the full page for this block

Retrieved Context Chunks

The RAG debugging surface: ranked passages with similarity as a meter, matched spans in real mark elements, and filter chips wired as a radiogroup so arrows move between them.

Retrieval & Context327 lines1 dep
Open the full page for this block

Answer Source Citations

The published footnotes under an answer — ordered list, real cite and time elements, the claim each source supports, and a staleness warning written in words rather than shown as an amber dot.

Retrieval & Context231 lines1 dep
Open the full page for this block

Knowledge Source Picker

Choosing what the assistant may read, with indexing state told honestly — a half-indexed source says so rather than showing a green tick — and the footer stating the effect of the selection, not its cardinality.

Retrieval & Context345 lines1 dep
Open the full page for this block

Nothing Found, Answered Honestly

The refusal screen: says plainly that nothing was found, shows where it looked and the near-misses below threshold, and offers the two real ways out instead of inventing an answer.

Retrieval & Context180 lines1 dep
Open the full page for this block

Index Freshness Panel

A green tick means the connector works, not that the answers are current. Freshness as an age in words per source, the headline taken from the stalest one, and a failed sync that still says what age it is answering from.

Retrieval & Context246 lines1 dep
Open the full page for this block

Retrieval Freshness List

Retrieved sources ranked by how stale they are, because a confident answer from a two-year-old document is the failure people do not catch.

Retrieval & Context151 linesNo deps
Open the full page for this block

Context Scope List

Which sources this answer may draw on, shown as a scope the user can read before asking rather than a citation list after.

Retrieval & Context152 linesNo deps
Open the full page for this block

Grounding Split

How an answer is tied to its sources, and what the system does when it cannot find any.

Retrieval & Context156 linesNo deps