Baseline Widget

A compact panel that lays a set of current measurements next to the baseline you're comparing them against. Each row renders the value, the baseline, the signed delta, and a verdict chip — colored by whether the metric moved in the right direction. Drop it into a lesson, a perf dashboard, or a release-day audit.

Preview

Baseline audit

Comparing the latest run against last week's baseline.

  • LCP1.82sms−580ms · −24.2%
  • INP168ms+28ms · +20.0%
  • CLS0.060 · 0.0%
  • Bundle184KB−56KB · −23.3%
  • Lighthouse92+14 · +17.9%
Customize
Current values
1820ms
168ms
184KB
92
Options

Installation

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

Usage

import { BaselineWidget } from "@craft-bits/core";
 
<BaselineWidget
  title="Baseline audit"
  metrics={[
    { id: "lcp", label: "LCP", value: 1820, baseline: 2400, unit: "ms" },
    { id: "inp", label: "INP", value: 168, baseline: 140, unit: "ms" },
    { id: "bundle", label: "Bundle", value: 184, baseline: 240, unit: "KB" },
  ]}
/>

Flip a single row to "higher is better" for scores and accuracy KPIs:

<BaselineWidget
  metrics={[
    {
      id: "score",
      label: "Lighthouse",
      value: 92,
      baseline: 78,
      direction: "higher-is-better",
    },
  ]}
/>

Anatomy

  • Header. Optional title (renders with the cb-label style) and a description sub-line. Omit both for a chromeless panel.
  • Row. One <li> per metric. The label sits left, the current value mid-row, the baseline next to it, and the signed delta on the right. The verdict chip rides the delta.
  • Verdict tone. good paints --cb-success, bad paints --cb-error, neutral paints --cb-fg. The chip and the delta share the same color so the eye picks up both at once.

Understanding the component

  1. Direction. direction (or metric.direction) flips which sign counts as Better. Default is lower-is-better — most performance metrics want to shrink.
  2. Tolerance. metric.tolerance declares a dead zone — a delta inside the tolerance reads as neutral even if it has the wrong sign. Use it for noisy signals like CLS.
  3. Delta format. deltaFormat="absolute" | "percent" | "both" picks the right column shape. Default is both.
  4. Formatter. Each metric can supply its own format(value) function. The default switches ms to s past 1000 and KB to MB past 1000, and adapts decimal places to the magnitude.
  5. Motion. Value cells re-animate when the value changes (spring snap). The animation short-circuits under prefers-reduced-motion.

Props

PropTypeDefaultDescription
metricsBaselineWidgetMetric[]requiredOrdered metric rows.
titleReactNodeOptional heading above the rail.
descriptionReactNodeOptional sub-headline under the title.
direction'lower-is-better' | 'higher-is-better''lower-is-better'Default direction for all metrics.
deltaFormat'absolute' | 'percent' | 'both''both'Delta column shape.
hideRatingbooleanfalseHide the verdict chip.
headingAs'h2' | 'h3' | 'h4''h3'Tag for the title element.
classNamestringMerged onto the root via cn().

BaselineWidgetMetric

FieldTypeDescription
idstringStable identifier.
labelReactNodeVisible row label.
valuenumberCurrent measurement.
baselinenumberReference value — when omitted, the delta is rendered as a dash.
unitstringDisplay unit (e.g. ms, KB).
direction'lower-is-better' | 'higher-is-better'Override the widget-level direction.
format(value) => stringCustom formatter.
tolerancenumberDead zone around the baseline.

Accessibility

  • The wrapper is a <section> with data-cb-edu="baseline-widget". Rows form a role="list" of role="listitem" entries so screen readers announce them as a sequence.
  • The metric grid uses aria-live="polite" — value updates are announced without interrupting the user.
  • Each row exposes data-cb-verdict="good" | "neutral" | "bad" so consumers can extend tone-specific styling without monkey-patching CSS.
  • The baseline and delta cells carry descriptive aria-label text so verdicts are conveyed without depending on color.
  • Animations are limited to the value cell and short-circuit under prefers-reduced-motion.

Credits

  • Extracted from: terminal-dreams (src/components/frontend-design/sdp-web-performance/ui/BaselineWidget.tsx). The original pulled a PerfMetrics object out of a PerfContext and delegated rendering to a project-specific MetricsPanel. This rewrite drops the context dependency and the fixed CWV gauge set — consumers pass their own metric/value/baseline/unit rows so the widget covers any baseline-comparison use case, not just web vitals.