Caching Widget
A compact panel that walks through a list of cache lookups and shows, per request, whether the lookup hit or missed, the TTL on the cached entry, and an optional cost column for size or latency. A summary line at the bottom reports the overall hit-rate with a small meter — drop it into a perf lesson, a CDN dashboard, or anywhere you want a "what's cached, what's not" reading.
Preview
Cache log
Five sequential lookups against a CDN with mixed cache-control.
- index.htmlMISSno-cache12 KB
- styles.cssHIT1y48 KB
- main.[hash].jsMISS1y385 KB
- hero.jpgHIT1mo245 KB
- GET /api/feedHIT5m8 KB
Hit rate60%(3/5)
Customize
Outcomes
API TTL
300s
Options
Installation
npx shadcn@latest add https://craftbits.dev/r/caching-widget.jsonUsage
import { CachingWidget } from "@craft-bits/core";
<CachingWidget
title="Cache log"
requests={[
{ id: "html", key: "index.html", hit: false, ttl: 0, cost: "12 KB" },
{ id: "css", key: "styles.css", hit: true, ttl: 31536000, cost: "48 KB" },
{ id: "api", key: "GET /api/feed", hit: true, ttl: 300, cost: "8 KB" },
]}
/>Provide your own TTL formatter for project-specific units:
<CachingWidget
requests={requests}
formatTtl={(s) => (s >= 86400 ? `${Math.floor(s / 86400)} days` : `${s} s`)}
/>Anatomy
- Header. Optional
title(rendered with thecb-labelstyle) anddescription. Omit both for a chromeless panel. - Row. One
<li>per request. The cache key sits on the left in monospace, the outcome chip (HIT/MISS) sits next to it, the formatted TTL after that, and an optionalcostlabel on the right. - Outcome tone.
hitpaints--cb-success;misspaints--cb-error. The chip and the cost share the same tone so the eye picks up both at once. - Summary. A hit-rate meter renders under the log. It paints green at 100%, red at 0%, and neutral in between. Hide it entirely with
hideSummary.
Understanding the component
- Hit vs miss. Each request carries a boolean
hit. The widget computes the outcome tone, the per-row chip, and the aggregate hit-rate from this single flag — consumers never have to compute the rate themselves. - TTL formatting. The built-in formatter compacts seconds into shorthand like
30s,5m,1h,30d,1y. Negative values render asexpired, zero asno-cache, and an omittedttlrenders as a dash so uncacheable resources can be listed alongside cached ones. - Cost column. The
costfield is a free-formReactNode. Use it for sizes (e.g.245 KB), latencies (e.g.38ms), or whichever cost dimension your lesson cares about. Hidden on small viewports to keep the row scannable. - Motion. Outcome chips re-animate when the row changes (spring
snap), and the hit-rate bar re-fills whenever the totals shift. Both animations short-circuit underprefers-reduced-motion.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
requests | CachingWidgetRequest[] | required | Ordered list of cache lookups. |
title | ReactNode | — | Optional heading above the log. |
description | ReactNode | — | Optional sub-headline under the title. |
formatTtl | (seconds) => string | magnitude-aware default | Custom TTL formatter. |
hideSummary | boolean | false | Hide the hit-rate summary block. |
headingAs | 'h2' | 'h3' | 'h4' | 'h3' | Tag for the title element. |
className | string | — | Merged onto the root via cn(). |
CachingWidgetRequest
| Field | Type | Description |
|---|---|---|
id | string | Stable identifier. |
key | ReactNode | Cache key being looked up. |
hit | boolean | Whether the lookup hit the cache. |
ttl | number | TTL in seconds. Omit for uncacheable entries. |
cost | ReactNode | Optional size/latency label. |
Accessibility
- The wrapper is a
<section>withdata-cb-edu="caching-widget". Rows form arole="list"ofrole="listitem"entries so screen readers announce them as a sequence. - The row grid uses
aria-live="polite"— updates are announced without interrupting the user. - Each row exposes
data-cb-outcome="hit" | "miss"so consumers can extend tone-specific styling without monkey-patching CSS. - The TTL cell carries an
aria-labellikettl 5m, and the hit-rate meter is arole="progressbar"with descriptivearia-label, so the verdict is conveyed without depending on color. - Animations are limited to the chip and the meter, and short-circuit under
prefers-reduced-motion.
Credits
- Extracted from:
terminal-dreams(src/components/frontend-design/sdp-web-performance/ui/CachingWidget.tsx). The original pulled aPerfContextfor network multipliers and visit type, hard-coded an uncached / cached waterfall against a fixed cache-strategy table, and was tightly bound to the perf lab. This rewrite drops the context and the strategy table — consumers pass their own{ key, hit, ttl, cost }requests and the widget covers any cache-log use case.