All Taste components
Data display
Stat card
A headline number with its change against last period and a small trend line.
up · down · good-when-down · sparkline
Revenue, October₹4,82,30012.4%vs September
Outstanding₹1,26,0008.1%lower is better
Overdue invoices72since last week
import { ArrowDownRight, ArrowUpRight } from "lucide-react";
import { cn } from "@/lib/utils";
/** values → SVG paths in a 120×36 box. */
function sparkPaths(values: number[]) {
const max = Math.max(...values), min = Math.min(...values);
const line = values
.map((v, i) => (i ? "L" : "M") + ((i / (values.length - 1)) * 120).toFixed(1) + "," + (32 - ((v - min) / (max - min || 1)) * 28).toFixed(1))
.join(" ");
return { line, area: line + " L120,36 L0,36 Z" };
}
export function StatCard({ label, value, change, direction, good, caption, trend }: {
label: string;
value: string;
change: string;
direction: "up" | "down";
/** Whether this change is good news — colours the chip, not the arrow. */
good: boolean;
caption: string;
trend: number[];
}) {
const { line, area } = sparkPaths(trend);
const Arrow = direction === "up" ? ArrowUpRight : ArrowDownRight;
return (
<div className="grid min-w-0 gap-1 rounded-lg border border-border bg-bg p-4">
<p className="text-[13px] font-medium text-fg-muted">{label}</p>
<p className="text-2xl font-semibold tabular-nums tracking-tight">{value}</p>
<p className="flex items-center gap-1.5 text-[12.5px] text-fg-subtle">
<span className={cn(
"inline-flex h-5 items-center gap-0.5 rounded-full px-1.5 text-xs font-medium tabular-nums",
good ? "bg-success-soft text-success-fg" : "bg-danger-soft text-danger-fg",
)}>
<Arrow className="size-3" aria-hidden />{change}
</span>
{caption}
</p>
<svg viewBox="0 0 120 36" preserveAspectRatio="none" className="mt-2 h-9 w-full overflow-visible" role="img" aria-label={label + " trend"}>
<path d={area} className="fill-primary/10" />
<path d={line} fill="none" className="stroke-primary" strokeWidth={1.75} strokeLinecap="round" strokeLinejoin="round" vectorEffect="non-scaling-stroke" />
</svg>
</div>
);
}
// <div className="grid grid-cols-[repeat(auto-fit,minmax(180px,1fr))] gap-3">
// <StatCard label="Revenue, October" value="₹4,82,300" change="12.4%" direction="up" good caption="vs September" trend={[22, 24, 23, 28, 26, 31, 30, 35, 34, 39, 41]} />
// <StatCard label="Outstanding" value="₹1,26,000" change="8.1%" direction="down" good caption="lower is better" trend={[40, 38, 39, 34, 35, 31, 32, 27, 28, 24, 22]} />
// </div>
The code uses the Taste Tailwind preset. Make yours on the Taste page with Export my system.