Live KPI Ticker
An endless, seamless marquee of KPIs — value, semantic-colored delta, and a sparkline each — that pauses on hover and off-screen. The 'this dashboard is alive' strip.
Acme · live metrics
1.8k
Monthly signups · +31.0%
Tracking 8 KPIs live — 5 up, 3 down; Monthly signups is moving most (+31.0%).
MRR
$4.8M
Headcount
210
Churn
2.5%
NPS
62
p99 latency
185 ms
Support queue
42
Monthly signups
1.8k
ARPU
$2.1k
MRR
$4.8M
Headcount
210
Churn
2.5%
NPS
62
p99 latency
185 ms
Support queue
42
Monthly signups
1.8k
ARPU
$2.1k
| KPI | Value | Change |
|---|---|---|
| MRR | $4.8M | +18.2% |
| Headcount | 210 | +6.5% |
| Churn | 2.5% | -14.0% |
| NPS | 62 | +8.0% |
| p99 latency | 185 ms | -11.0% |
| Support queue | 42 | -28.0% |
| Monthly signups | 1.8k | +31.0% |
| ARPU | $2.1k | +12.0% |
Acme analytics · updated every 60 sec
Demo data is illustrative. Replace with your own typed data prop.
Use it with your data
Data contract
Passed via the data prop — an object: validated at runtime, so a bad shape degrades to the error state rather than crashing.
| Field | Type | Required |
|---|---|---|
| items | array | yes |
Static props
import { ChartKpiTicker } from "@/components/blocks/chart-kpi-ticker/chart-kpi-ticker";
<ChartKpiTicker data={myData} />Client fetch (SWR)
const { data, isLoading, error } = useSWR("/api/metric", fetcher);
// route isLoading/error through <ChartStates>, then:
<ChartKpiTicker data={data} />Server component (RSC)
const data = await fetch(url, {
next: { revalidate: 3600 },
}).then((r) => r.json());
<ChartKpiTicker data={data} />Map arbitrary rows
import { mapRows } from "@/lib/sextant/column-map";
const out = mapRows(rows, { /* contractKey: "yourColumn" */ }, dataSchema);
if (out.ok) <ChartKpiTicker data={out.data} />;Make it yours
Every customization below is an optional prop — omit them all and you get the defaults shown above. Recolor, reformat, restyle, or drop the card chrome without forking the component.
Recolor or rename a series (accent)
<ChartKpiTicker
series={{ accent: { color: "var(--chart-3)", label: "…" } }}
/>Replace or hide the narrative
<ChartKpiTicker narrative="Your own one-liner." />
// …or hide it entirely:
<ChartKpiTicker narrative={false} />Restyle any region
<ChartKpiTicker
className="max-w-xl"
classNames={{ body: "bg-muted/20" }}
/>