Stat Card
A card for displaying metrics with label, value, and optional trend indicator. Built using Box, Column, Row, Icon, and Text components.
Total Users
12,345+12%vs last month
Revenue
$54,321-3.2%vs last month
Source
'use client';
import { ArrowDown, ArrowUp, Minus } from 'lucide-react';
import { Box, Column, Icon, Row, Text } from '@umami/react-zen';
export function StatCard({ label, value, change, icon, trend, ...props }) {
const trendColor = trend === 'up' ? 'green' : trend === 'down' ? 'red' : 'muted';
const TrendIcon = trend === 'up' ? ArrowUp : trend === 'down' ? ArrowDown : Minus;
return (
<Box
padding="4"
backgroundColor="surface-raised"
borderRadius="lg"
border
borderColor="muted"
{...props}
>
<Column gap="3">
<Row alignItems="center" justifyContent="space-between">
<Text color="muted">{label}</Text>
{icon && <Icon size="sm" color="muted">{icon}</Icon>}
</Row>
<Text size="2xl" weight="semibold">{value}</Text>
{change && (
<Row alignItems="center" gap="1">
<Icon size="sm" color={trendColor}><TrendIcon /></Icon>
<Text color={trendColor}>
{change.value > 0 ? '+' : ''}{change.value}%
</Text>
{change.label && <Text color="muted">{change.label}</Text>}
</Row>
)}
</Column>
</Box>
);
}
export function StatCardGroup({ children, ...props }) {
return (
<Row gap="4" flexWrap="wrap" {...props}>
{children}
</Row>
);
}
export function StatCardCompact({ label, value, subValue }) {
return (
<Column gap="1">
<Text color="muted" transform="uppercase">{label}</Text>
<Row alignItems="baseline" gap="1">
<Text size="xl" weight="semibold">{value}</Text>
{subValue && <Text color="muted">{subValue}</Text>}
</Row>
</Column>
);
}Variations
Compact inline stats
Users
12.3k+12%
Revenue
$54k-3%
Orders
1,234
Without icon
Page Views
45,678+8.5%
Bounce Rate
32.1%-2.3%
In a group
Total Sales
$123,456+15%
Orders
1,234+8%
Customers
567