KPI card
A metric with delta, hint and an optional sparkline.
$
pnpm dlx shadcn@latest add https://lodeui.com/r/kpi-card.jsonMRR
$42,810
6.2%vs last month
Active users
12,480
3.1%
p95 latency
184ms
12.5%lower is better
components/examples/kpi-card-demo.tsx
"use client";
import { DollarSign, Timer, Users } from "lucide-react";
import { KpiCard } from "@/components/ui/kpi-card";
import { Sparkline } from "@/components/ui/sparkline";
export default function KpiCardDemo() {
return (
<div className="grid w-full max-w-3xl gap-3 sm:grid-cols-3">
<KpiCard label="MRR" icon={<DollarSign />} value="$42,810" delta={6.2} hint="vs last month" chart={<Sparkline data={[30, 31, 33, 32, 35, 37, 41, 42]} width={64} />} />
<KpiCard label="Active users" icon={<Users />} value="12,480" delta={3.1} chart={<Sparkline data={[11, 11.4, 11.2, 11.8, 12, 12.1, 12.4]} width={64} />} />
<KpiCard label="p95 latency" icon={<Timer />} value="184ms" delta={-12.5} invert hint="lower is better" />
</div>
);
}When to use
- A headline metric with its change and a small trend.
When not to use
- Detailed analysis: use a chart.
Installation
$
pnpm dlx shadcn@latest add https://lodeui.com/r/kpi-card.json1Install the dependencies
npm install lucide-react2Copy the source into your project
components/ui/kpi-card.tsximport * as React from "react"; import { ArrowDownRight, ArrowUpRight } from "lucide-react"; import { cn } from "@/lib/utils"; export interface KpiCardProps { label: string; value: React.ReactNode; /** Percent or points change vs the comparison period. */ delta?: number; deltaSuffix?: string; /** Lower is better (e.g. churn, latency): flips the color logic. */ invert?: boolean; hint?: React.ReactNode; /** A small chart, e.g. <Sparkline />. */ chart?: React.ReactNode; icon?: React.ReactNode; className?: string; } export function KpiCard({ label, value, delta, deltaSuffix = "%", invert, hint, chart, icon, className }: KpiCardProps) { const good = delta === undefined ? undefined : invert ? delta <= 0 : delta >= 0; return ( <div className={cn("flex flex-col justify-between gap-3 rounded-lg border border-border bg-card p-4", className)}> <div className="flex items-center justify-between gap-2"> <p className="text-sm text-muted-foreground">{label}</p> {icon && <span className="text-muted-foreground [&_svg]:size-4">{icon}</span>} </div> <div className="flex items-end justify-between gap-3"> <div className="min-w-0"> <p className="truncate text-2xl font-semibold tracking-tight tabular-nums">{value}</p> <div className="mt-1 flex items-center gap-1.5 text-xs"> {delta !== undefined && ( <span className={cn("inline-flex items-center gap-0.5 font-medium tabular-nums", good ? "text-emerald-600 dark:text-emerald-400" : "text-destructive")}> {delta >= 0 ? <ArrowUpRight className="size-3.5" /> : <ArrowDownRight className="size-3.5" />} {Math.abs(delta).toFixed(1)} {deltaSuffix} </span> )} {hint && <span className="text-muted-foreground">{hint}</span>} </div> </div> {chart && <div className="shrink-0">{chart}</div>} </div> </div> ); }
Usage
Import it from @/components/ui/kpi-card after installing.
example.tsx
import { KpiCard } from "@/components/ui/kpi-card";
import { Sparkline } from "@/components/ui/sparkline";
export function Churn() {
return <KpiCard label="Churn" value="2.1%" delta={-0.4} deltaSuffix="pts" invert chart={<Sparkline data={[3, 2.8, 2.5, 2.1]} />} />;
}API reference
KpiCard
Label, value, colored delta, hint and optional chart.
| Prop | Type | Default | Description |
|---|---|---|---|
| label / value | string / ReactNode | – | Pass a NumberTicker as value for animation. |
| delta / deltaSuffix | number / string | — / "%" | Change vs the comparison period. |
| invert | boolean | – | Lower is better (churn, latency): flips green and red. |
| hint / chart / icon | ReactNode | – | Extras. |
Accessibility
- The delta includes an arrow and sign, not just color.
Motion
- Inherits motion from what you pass as value or chart.
Responsive behavior
- Fills its grid cell; use a 2-column grid on phones.
Performance
- Static.
Notes for AI
- Set invert for metrics where going down is good.
This page as Markdown, for assistants and coding agents:
/components/kpi-card/markdownThe full library index for assistants is at /llms.txt.
Lode222 doc pagesllms.txt