Clawscale

Metric

A Metric shows a labeled headline number with an optional change and trend. Use it for KPI rows and dashboard tiles.

Usage#

import { Metric } from "@clawscale/react";
<Metric label="Throughput" value="12,480" unit="rows/s" delta={8.2} />

Examples#

Basic#

label names the number and value shows it. Pass the value formatted, with separators and precision.

Active pipelines
38
Rows ingested today
1.84B
import { Metric } from "@clawscale/react";

export default function MetricBasic() {
  return (
    <div style={{ display: "flex", gap: 40 }}>
      <Metric label="Active pipelines" value="38" />
      <Metric label="Rows ingested today" value="1.84B" />
    </div>
  );
}

Unit and delta#

unit follows the value in muted text. delta adds a Delta below it, a percentage by default. deltaFormat changes the format.

Throughput
12,480rows/s
Cache hit rate
94.1%
import { Metric } from "@clawscale/react";

export default function MetricUnitDelta() {
  return (
    <div style={{ display: "flex", gap: 40 }}>
      <Metric label="Throughput" value="12,480" unit="rows/s" delta={8.2} />
      <Metric label="Cache hit rate" value="94.1" unit="%" delta={-1.2} />
    </div>
  );
}

Good direction#

Set goodDirection="down" when lower is better, as for latency, cost or error rate. A rise then reads as bad.

p95 latency
182ms
Error rate
0.42%
import { Metric } from "@clawscale/react";

export default function MetricGoodDirection() {
  return (
    <div style={{ display: "flex", gap: 40 }}>
      <Metric label="p95 latency" value="182" unit="ms" delta={3.1} goodDirection="down" />
      <Metric label="Error rate" value="0.42" unit="%" delta={-12.5} goodDirection="down" />
    </div>
  );
}

Caption#

caption adds short context next to the delta, usually the comparison period.

Throughput
12,480rows/s
Queued jobs
1,204
import { Metric } from "@clawscale/react";

export default function MetricCaption() {
  return (
    <div style={{ display: "flex", gap: 40 }}>
      <Metric label="Throughput" value="12,480" unit="rows/s" delta={8.2} caption="vs last hour" />
      <Metric label="Queued jobs" value="1,204" caption="across 6 regions" />
    </div>
  );
}

Trend#

trend draws a Sparkline under the value, oldest point first. Set trendColor to the chart slot the same series uses elsewhere on the screen.

Ingest, us-east-1
9,400rows/s
Ingest, eu-west-1
6,100rows/s
import { Metric } from "@clawscale/react";

const usEast = [8120, 8340, 8290, 8610, 8580, 8870, 8930, 9050, 9120, 9260, 9310, 9400];
const euWest = [6480, 6420, 6510, 6390, 6300, 6340, 6250, 6220, 6180, 6150, 6120, 6100];

export default function MetricTrend() {
  return (
    <div style={{ display: "grid", gap: 40, gridTemplateColumns: "repeat(2, 180px)" }}>
      <Metric label="Ingest, us-east-1" value="9,400" unit="rows/s" trend={usEast} />
      <Metric label="Ingest, eu-west-1" value="6,100" unit="rows/s" trend={euWest} trendColor="var(--cs-chart-2)" />
    </div>
  );
}

Size#

size accepts small, medium (default) and large. It scales the value. The label and footer keep their size.

Small
1,204jobs
Medium
1,204jobs
Large
1,204jobs
import { Metric } from "@clawscale/react";

export default function MetricSize() {
  return (
    <div style={{ display: "flex", gap: 40 }}>
      <Metric size="small" label="Small" value="1,204" unit="jobs" />
      <Metric size="medium" label="Medium" value="1,204" unit="jobs" />
      <Metric size="large" label="Large" value="1,204" unit="jobs" />
    </div>
  );
}

Loading#

loading swaps the value for a skeleton and sets aria-busy. The label stays, so nothing shifts when data arrives. The delta and trend do not turn into skeletons: pass them once you have them.

Throughput
12,480rows/s
import { Metric, Switch } from "@clawscale/react";
import { useState } from "react";

export default function MetricLoading() {
  const [loading, setLoading] = useState(true);
  return (
    <div style={{ display: "grid", gap: 16, width: 180 }}>
      <Metric label="Throughput" value="12,480" unit="rows/s" loading={loading} />
      <Switch label="Loading" checked={loading} onChange={(event) => setLoading(event.currentTarget.checked)} />
    </div>
  );
}

Metric grid#

Put each metric in a compact Card and lay the cards out in a CSS grid. Long labels truncate instead of wrapping.

Throughput
12,480rows/s
p95 latency
182ms
Error rate
0.42%
Active pipelines
38
Rows ingested
1.84B
Compute cost
$1,284
import { Card, Metric } from "@clawscale/react";

const metrics = [
  { label: "Throughput", value: "12,480", unit: "rows/s", delta: 8.2 },
  { label: "p95 latency", value: "182", unit: "ms", delta: 3.1, goodDirection: "down" },
  { label: "Error rate", value: "0.42", unit: "%", delta: -12.5, goodDirection: "down" },
  { label: "Active pipelines", value: "38", delta: 0 },
  { label: "Rows ingested", value: "1.84B", delta: 4.6 },
  { label: "Compute cost", value: "$1,284", delta: 1.9, goodDirection: "down" },
] as const;

export default function MetricGrid() {
  return (
    <div style={{ display: "grid", gap: 12, gridTemplateColumns: "repeat(auto-fill, minmax(180px, 1fr))" }}>
      {metrics.map((metric) => (
        <Card key={metric.label} compact>
          <Metric size="small" caption="vs yesterday" {...metric} />
        </Card>
      ))}
    </div>
  );
}

Interactive playground#

p95 latency
182ms
Props
-50.0
50.0
3.1
Open dropdown
View source on GitHub

Props interface#

Metric also accepts the HTML attributes of a div.

interface MetricProps extends Omit<HTMLAttributes<HTMLDivElement>, "title">@clawscale/react
PropsDescription
caption
ReactNode
Short context under the value, such as "vs last week".
delta
number
Change since the comparison period. Renders a Delta.
deltaFormat
DeltaProps["format"]
Formats the delta. See Delta.
goodDirection
DeltaProps["goodDirection"] = "up"
Direction that counts as good for the delta.
labelrequired
ReactNode
What the number measures.
loading
boolean
Show a skeleton instead of the value.
size
"small" | "medium" | "large" = "medium"
Visual size.
trend
readonly number[]
Trend data. Renders a Sparkline under the value.
trendColor
string = "var(--cs-chart-1)"
Sparkline color.
unit
ReactNode
Unit shown after the value, such as "ms" or "GB".
valuerequired
ReactNode
The headline value. Pass it formatted.