Metric card
One metric in an 8px frame with concentric corners, then its title and one sentence.
Repeat customers
41%
+6 points since July
People come back
Two in five buyers ordered again within 60 days.
Installation
$ pnpm dlx shadcn@latest add @ssntl/metric-cardUsage
import { MetricCard, MetricCardBody, MetricCardPanel, MetricCardText, MetricCardTitle } from "@/components/ui/metric-card"
<MetricCard>
<MetricCardPanel>{/* a Stat or a chart */}</MetricCardPanel>
<MetricCardText>
<MetricCardTitle>People come back</MetricCardTitle>
<MetricCardBody>Two in five buyers ordered again within 60 days.</MetricCardBody>
</MetricCardText>
</MetricCard>- Breathing room from one rhythm: an 8px frame, 24px inside the panel, 16px around the text.
- Concentric corners: the panel takes the card's 32px minus the 8px frame (needs the radius-concentric utility, installed with it).
- One metric per card; the title states the finding, the body gives one sentence of context.
Code
import * as React from "react"
import { cn } from "@/lib/utils"
// Essential Design MetricCard: a white shell with an 8px frame around a muted
// panel that holds one piece of evidence, then its title and one sentence.
// Breathing room comes from one rhythm: 8px frame, 24px inside the panel,
// 16px around the text. Concentric: the panel takes 32 − 8 = 24px.
function MetricCard({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="metric-card"
className={cn(
"grid content-start rounded-outer-lg bg-card p-concentric-2 shadow-float",
className
)}
{...props}
/>
)
}
function MetricCardPanel({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="metric-card-panel"
className={cn("rounded-inner bg-muted p-6", className)}
{...props}
/>
)
}
function MetricCardText({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="metric-card-text"
className={cn("grid gap-1 p-4", className)}
{...props}
/>
)
}
function MetricCardTitle({ className, ...props }: React.ComponentProps<"h3">) {
return (
<h3
data-slot="metric-card-title"
className={cn("text-heading", className)}
{...props}
/>
)
}
function MetricCardBody({ className, ...props }: React.ComponentProps<"p">) {
return (
<p
data-slot="metric-card-body"
className={cn("text-body text-pretty text-muted-foreground", className)}
{...props}
/>
)
}
export {
MetricCard,
MetricCardBody,
MetricCardPanel,
MetricCardText,
MetricCardTitle,
}