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.htmlMISS
  • styles.cssHIT
  • main.[hash].jsMISS
  • hero.jpgHIT
  • GET /api/feedHIT
Hit rate60%(3/5)
Customize
Outcomes
API TTL
300s
Options

Installation

npx shadcn@latest add https://craftbits.dev/r/caching-widget.json

Usage

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 the cb-label style) and description. 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 optional cost label on the right.
  • Outcome tone. hit paints --cb-success; miss paints --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

  1. 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.
  2. TTL formatting. The built-in formatter compacts seconds into shorthand like 30s, 5m, 1h, 30d, 1y. Negative values render as expired, zero as no-cache, and an omitted ttl renders as a dash so uncacheable resources can be listed alongside cached ones.
  3. Cost column. The cost field is a free-form ReactNode. 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.
  4. 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 under prefers-reduced-motion.

Props

PropTypeDefaultDescription
requestsCachingWidgetRequest[]requiredOrdered list of cache lookups.
titleReactNodeOptional heading above the log.
descriptionReactNodeOptional sub-headline under the title.
formatTtl(seconds) => stringmagnitude-aware defaultCustom TTL formatter.
hideSummarybooleanfalseHide the hit-rate summary block.
headingAs'h2' | 'h3' | 'h4''h3'Tag for the title element.
classNamestringMerged onto the root via cn().

CachingWidgetRequest

FieldTypeDescription
idstringStable identifier.
keyReactNodeCache key being looked up.
hitbooleanWhether the lookup hit the cache.
ttlnumberTTL in seconds. Omit for uncacheable entries.
costReactNodeOptional size/latency label.

Accessibility

  • The wrapper is a <section> with data-cb-edu="caching-widget". Rows form a role="list" of role="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-label like ttl 5m, and the hit-rate meter is a role="progressbar" with descriptive aria-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 a PerfContext for 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.