Stat
A flexible component for displaying key metrics and statistics with support for trends, indicators, and descriptions.
import {
ArrowDown,
ArrowUp,
DollarSign,
MoreHorizontal,
ShoppingCart,
} from "lucide-react";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
Stat,
StatIndicator,
StatLabel,
StatTrend,
StatValue,
} from "@/components/ui/stat";
export function StatDemo() {
return (
<div className="grid gap-4 sm:grid-cols-2">
<Stat>
<StatLabel>Total Revenue</StatLabel>
<StatIndicator variant="icon" color="success">
<DollarSign />
</StatIndicator>
<StatValue>$45,231</StatValue>
<StatTrend trend="up">
<ArrowUp />
+20.1% from last month
</StatTrend>
</Stat>
<Stat>
<StatLabel>Active Users</StatLabel>
<StatIndicator variant="badge" color="info">
+24
</StatIndicator>
<StatValue>2,350</StatValue>
<StatTrend trend="up">
<ArrowUp />
+180 from last week
</StatTrend>
</Stat>
<Stat>
<StatLabel>Total Orders</StatLabel>
<StatIndicator variant="icon" color="warning">
<ShoppingCart />
</StatIndicator>
<StatValue>1,234</StatValue>
<StatTrend trend="down">
<ArrowDown />
-4.3% from last month
</StatTrend>
</Stat>
<Stat>
<StatLabel>Conversion Rate</StatLabel>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<StatIndicator variant="action">
<MoreHorizontal />
</StatIndicator>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem>View details</DropdownMenuItem>
<DropdownMenuItem>Export data</DropdownMenuItem>
<DropdownMenuItem>Share</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
<StatValue>3.2%</StatValue>
<StatTrend trend="neutral">No change from last week</StatTrend>
</Stat>
</div>
);
}Installation
CLI
npx shadcn@latest add @diceui/statManual
Copy and paste the following code into your project.
import { cva, type VariantProps } from "class-variance-authority";
import type * as React from "react";
import { Separator } from "@/components/ui/separator";
import { cn } from "@/lib/utils";
function Stat({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="stat"
className={cn(
"grid grid-cols-[1fr_auto] gap-x-4 gap-y-1 rounded-lg border bg-card p-4 text-card-foreground shadow-sm",
"**:data-[slot=stat-label]:col-span-1 **:data-[slot=stat-value]:col-span-1",
"**:data-[slot=stat-indicator]:col-start-2 **:data-[slot=stat-indicator]:row-span-2 **:data-[slot=stat-indicator]:row-start-1 **:data-[slot=stat-indicator]:self-start",
"**:data-[slot=stat-description]:col-span-2 **:data-[slot=stat-separator]:col-span-2 **:data-[slot=stat-trend]:col-span-2",
className,
)}
{...props}
/>
);
}
function StatLabel({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="stat-label"
className={cn("font-medium text-muted-foreground text-sm", className)}
{...props}
/>
);
}
const statIndicatorVariants = cva(
"flex shrink-0 items-center justify-center [&_svg]:pointer-events-none",
{
variants: {
variant: {
default: "text-muted-foreground [&_svg:not([class*='size-'])]:size-5",
icon: "size-8 rounded-md border [&_svg:not([class*='size-'])]:size-3.5",
badge:
"h-6 min-w-6 rounded-sm border px-1.5 font-medium text-xs [&_svg:not([class*='size-'])]:size-3",
action:
"size-8 cursor-pointer rounded-md transition-colors hover:bg-muted/50 [&_svg:not([class*='size-'])]:size-4",
},
color: {
default: "bg-muted text-muted-foreground",
success:
"border-green-500/20 bg-green-500/10 text-green-600 dark:text-green-400",
info: "border-blue-500/20 bg-blue-500/10 text-blue-600 dark:text-blue-400",
warning:
"border-orange-500/20 bg-orange-500/10 text-orange-600 dark:text-orange-400",
error: "border-destructive/20 bg-destructive/10 text-destructive",
},
},
defaultVariants: {
variant: "default",
color: "default",
},
},
);
interface StatIndicatorProps
extends Omit<React.ComponentProps<"div">, "color">,
VariantProps<typeof statIndicatorVariants> {}
function StatIndicator({
className,
variant = "default",
color = "default",
...props
}: StatIndicatorProps) {
return (
<div
data-slot="stat-indicator"
data-variant={variant}
data-color={color}
className={cn(statIndicatorVariants({ variant, color, className }))}
{...props}
/>
);
}
function StatValue({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="stat-value"
className={cn("font-semibold text-2xl tracking-tight", className)}
{...props}
/>
);
}
function StatTrend({
className,
trend,
...props
}: React.ComponentProps<"div"> & { trend?: "up" | "down" | "neutral" }) {
return (
<div
data-slot="stat-trend"
data-trend={trend}
className={cn(
"inline-flex items-center gap-1 font-medium text-xs [&_svg:not([class*='size-'])]:size-3 [&_svg]:pointer-events-none [&_svg]:shrink-0",
{
"text-green-600 dark:text-green-400": trend === "up",
"text-red-600 dark:text-red-400": trend === "down",
"text-muted-foreground": trend === "neutral" || !trend,
},
className,
)}
{...props}
/>
);
}
function StatSeparator({ ...props }: React.ComponentProps<typeof Separator>) {
return <Separator data-slot="stat-separator" className="my-2" {...props} />;
}
function StatDescription({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="stat-description"
className={cn("text-muted-foreground text-xs", className)}
{...props}
/>
);
}
export {
Stat,
StatLabel,
StatIndicator,
StatValue,
StatTrend,
StatSeparator,
StatDescription,
};Layout
Import the parts, and compose them together.
import {
Stat,
StatLabel,
StatValue,
StatIndicator,
StatTrend,
StatDescription,
StatSeparator,
} from "@/components/ui/stat";
return (
<Stat>
<StatLabel>Total Revenue</StatLabel>
<StatIndicator variant="icon" color="success">
<DollarSign />
</StatIndicator>
<StatValue>$45,231</StatValue>
<StatTrend trend="up">
<ArrowUp />
+20.1% from last month
</StatTrend>
<StatSeparator />
<StatDescription>
Total revenue generated in the current billing period
</StatDescription>
</Stat>
);Examples
Variants
Explore different indicator variants and color themes.
import { DollarSign, TrendingUp } from "lucide-react";
import {
Stat,
StatIndicator,
StatLabel,
StatTrend,
StatValue,
} from "@/components/ui/stat";
export function StatVariantsDemo() {
return (
<div className="grid gap-4 sm:grid-cols-2">
<Stat>
<StatLabel>Default Indicator</StatLabel>
<StatValue>2,350</StatValue>
<StatIndicator>
<TrendingUp />
</StatIndicator>
</Stat>
<Stat>
<StatLabel>Icon Variant</StatLabel>
<StatValue>$45,231</StatValue>
<StatIndicator variant="icon" color="success">
<DollarSign />
</StatIndicator>
</Stat>
<Stat>
<StatLabel>Badge Variant</StatLabel>
<StatValue>1,234</StatValue>
<StatIndicator variant="badge" color="info">
+24
</StatIndicator>
</Stat>
<Stat>
<StatLabel>Warning Color</StatLabel>
<StatValue>89%</StatValue>
<StatIndicator variant="icon" color="warning">
<TrendingUp />
</StatIndicator>
<StatTrend trend="down">Capacity threshold reached</StatTrend>
</Stat>
</div>
);
}Layout Options
Combine different stat components to create rich statistical displays.
import { ArrowUp, Users } from "lucide-react";
import {
Stat,
StatDescription,
StatIndicator,
StatLabel,
StatSeparator,
StatTrend,
StatValue,
} from "@/components/ui/stat";
export function StatLayoutDemo() {
return (
<div className="grid gap-4 sm:grid-cols-2">
<Stat>
<StatLabel>Active Subscribers</StatLabel>
<StatValue>2,847</StatValue>
<StatIndicator variant="icon" color="success">
<Users />
</StatIndicator>
<StatDescription>
Total number of active subscribers as of today
</StatDescription>
</Stat>
<Stat>
<StatLabel>Monthly Revenue</StatLabel>
<StatValue>$12,450</StatValue>
<StatIndicator variant="icon" color="info">
<ArrowUp />
</StatIndicator>
<StatSeparator />
<StatTrend trend="up">
<ArrowUp />
+15.3% from last month
</StatTrend>
<StatDescription>
Revenue generated in the current billing period
</StatDescription>
</Stat>
</div>
);
}API Reference
Stat
The main container component that provides a card-style layout for displaying statistics.
Prop
Type
StatLabel
A label component for the statistic title or category.
Prop
Type
StatIndicator
A visual indicator component that can display icons, badges, or action buttons with various color themes.
Prop
Type
| Data Attribute | Value |
|---|---|
[data-variant] | "default" | "icon" | "badge" | "action" |
[data-color] | "default" | "success" | "info" | "warning" | "error" |
StatValue
Displays the primary statistic value with emphasized typography.
Prop
Type
StatTrend
Displays trend information with directional styling (up, down, or neutral).
Prop
Type
| Data Attribute | Value |
|---|---|
[data-trend] | "up" | "down" | "neutral" |
StatSeparator
A horizontal separator for dividing content within the stat card.
Prop
Type
StatDescription
Additional descriptive text for providing context about the stat.