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.82sms2.40sms−580ms · −24.2%
- INP168ms140ms+28ms · +20.0%
- CLS0.060.060 · 0.0%
- Bundle184KB240KB−56KB · −23.3%
- Lighthouse9278+14 · +17.9%
Customize
Current values
1820ms
168ms
184KB
92
Options
Installation
npx shadcn@latest add https://craftbits.dev/r/baseline-widget.jsonUsage
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 thecb-labelstyle) and adescriptionsub-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.
goodpaints--cb-success,badpaints--cb-error,neutralpaints--cb-fg. The chip and the delta share the same color so the eye picks up both at once.
Understanding the component
- Direction.
direction(ormetric.direction) flips which sign counts asBetter. Default islower-is-better— most performance metrics want to shrink. - Tolerance.
metric.tolerancedeclares a dead zone — a delta inside the tolerance reads asneutraleven if it has the wrong sign. Use it for noisy signals like CLS. - Delta format.
deltaFormat="absolute" | "percent" | "both"picks the right column shape. Default isboth. - Formatter. Each metric can supply its own
format(value)function. The default switchesmstospast 1000 andKBtoMBpast 1000, and adapts decimal places to the magnitude. - Motion. Value cells re-animate when the value changes (spring
snap). The animation short-circuits underprefers-reduced-motion.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
metrics | BaselineWidgetMetric[] | required | Ordered metric rows. |
title | ReactNode | — | Optional heading above the rail. |
description | ReactNode | — | Optional 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. |
hideRating | boolean | false | Hide the verdict chip. |
headingAs | 'h2' | 'h3' | 'h4' | 'h3' | Tag for the title element. |
className | string | — | Merged onto the root via cn(). |
BaselineWidgetMetric
| Field | Type | Description |
|---|---|---|
id | string | Stable identifier. |
label | ReactNode | Visible row label. |
value | number | Current measurement. |
baseline | number | Reference value — when omitted, the delta is rendered as a dash. |
unit | string | Display unit (e.g. ms, KB). |
direction | 'lower-is-better' | 'higher-is-better' | Override the widget-level direction. |
format | (value) => string | Custom formatter. |
tolerance | number | Dead zone around the baseline. |
Accessibility
- The wrapper is a
<section>withdata-cb-edu="baseline-widget". Rows form arole="list"ofrole="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-labeltext 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 aPerfMetricsobject out of aPerfContextand delegated rendering to a project-specificMetricsPanel. This rewrite drops the context dependency and the fixed CWV gauge set — consumers pass their ownmetric/value/baseline/unitrows so the widget covers any baseline-comparison use case, not just web vitals.