Metric Cards

12 blocks

Metric Card 01

Preview
npx nateui@latest add MetricCardTrend
Dark
import Card from '@/components/ui/Card'
import { AreaChart } from '@/components/composites/Chart'
import { PiClock } from 'react-icons/pi'

const sessionTrend = [
    { day: 'Mon', value: 24 },
    { day: 'Tue', value: 18 },
    { day: 'Wed', value: 30 },
    { day: 'Thu', value: 26 },
    { day: 'Fri', value: 40 },
    { day: 'Sat', value: 34 },
    { day: 'Sun', value: 29 },
]

const MetricCardTrend = () => {
    return (
        <Card className="mx-auto w-full max-w-sm overflow-hidden">
            <div className="flex items-end gap-4">
                <div className="min-w-0 flex-1">
                    <div className="flex items-center gap-2">
                        <PiClock className="text-lg" />
                        <span>Average Session / Day</span>
                    </div>
                    <h4 className="mt-4 text-xl font-semibold">3.6 hrs</h4>
                    
                </div>
                <div className="w-32 shrink-0 sm:w-36 ">
                    <AreaChart
                        data={sessionTrend}
                        height={60}
                        chartHorizontalSpace={0}
                        chartVerticalSpace={0}
                        xAxisConfig={{ dataKey: 'day', hide: true }}
                        yAxisConfig={{ domain: [0, 'dataMax + 15'] }}
                        cartesianGridConfig={{ horizontal: false, vertical: false }}
                        areaConfig={[
                            {
                                dataKey: 'value',
                                name: 'Session',
                                stroke: 'var(--color-chart-1)',
                                fill: 'url(#metricCardTrendFill)',
                                strokeWidth: 2,
                            },
                        ]}
                    >
                        <defs>
                            <linearGradient id="metricCardTrendFill" x1="0" y1="0" x2="0" y2="1">
                                <stop offset="5%" stopColor="var(--color-chart-1)" stopOpacity={0.35} />
                                <stop offset="95%" stopColor="var(--color-chart-1)" stopOpacity={0} />
                            </linearGradient>
                        </defs>
                    </AreaChart>
                </div>
            </div>
        </Card>
    )
}

export default MetricCardTrend

Metric Card 02

Preview
npx nateui@latest add MetricCardProgress
Dark
import Card from '@/components/ui/Card'
import Button from '@/components/ui/Button'
import Tooltip from '@/components/ui/Tooltip'
import SegmentProgressBar from '@/components/composites/SegmentProgressBar'
import GrowShrinkTag from '@/components/composites/GrowShrinkTag'
import { PiInfo } from 'react-icons/pi'

const MetricCardProgress = () => {
    return (
        <Card className="mx-auto w-full max-w-sm">
            <div className="flex items-start justify-between gap-4">
                <h6 className="text-base font-medium">Active Listings</h6>
                <Tooltip title="Count of products currently active in your catalog.">
                    <Button
                        variant="ghost"
                        shape="circle"
                        size="sm"
                        icon={<PiInfo className="text-lg" />}
                        aria-label="About active listings"
                    />
                </Tooltip>
            </div>
            <div className="mt-4 flex items-baseline justify-between gap-4">
                <div className="flex items-baseline gap-2">
                    <h4 className="text-xl font-semibold">150</h4>
                    <GrowShrinkTag
                        value={4.5}
                        suffix="%"
                        className="border bg-transparent"
                    />
                </div>
                <p className="shrink-0 text-right leading-none">
                    <span className="font-semibold">80%</span>{' '}
                    <span className="text-muted-foreground">of goal</span>
                </p>
            </div>
            <SegmentProgressBar
                className="mt-2"
                segments={36}
                percent={80}
                height={28}
                filledClass="bg-success"
                gap={2}
            />
        </Card>
    )
}

export default MetricCardProgress

Metric Card 03

Preview
npx nateui@latest add MetricCardIconMenu
Dark
import Card from '@/components/ui/Card'
import Button from '@/components/ui/Button'
import Dropdown from '@/components/ui/Dropdown'
import IconFrame from '@/components/composites/IconFrame'
import GrowShrinkTag from '@/components/composites/GrowShrinkTag'
import { PiChartLineUp, PiDotsThreeOutlineVerticalFill } from 'react-icons/pi'

const MetricCardIconMenu = () => {
    return (
        <Card className="mx-auto w-full max-w-sm">
            <div className="flex items-start justify-between">
                <IconFrame variant="layered">
                    <PiChartLineUp className="text-xl" />
                </IconFrame>
                <Dropdown
                    placement="bottom-end"
                    renderTitle={
                        <Button
                            variant="ghost"
                            size="sm"
                            icon={<PiDotsThreeOutlineVerticalFill />}
                            aria-label="Metric options"
                        />
                    }
                >
                    <Dropdown.Item>View details</Dropdown.Item>
                    <Dropdown.Item>Export CSV</Dropdown.Item>
                </Dropdown>
            </div>

            <p className="mt-4">Signups ยท 24h</p>

            <div className="mt-1 flex items-baseline justify-between gap-4">
                <h4 className="text-xl font-semibold">3,200</h4>
                <div className="flex items-center gap-1">
                    <GrowShrinkTag
                        value={32}
                        suffix="%"
                        className="gap-1 border-0 bg-transparent p-0 text-sm font-semibold"
                    />
                    <span className="text-sm text-muted-foreground">vs prior month</span>
                </div>
            </div>
        </Card>
    )
}

export default MetricCardIconMenu

Metric Card 04

Preview
npx nateui@latest add MetricCardTrendWide
Dark
import Card from '@/components/ui/Card'
import GrowShrinkTag from '@/components/composites/GrowShrinkTag'
import { AreaChart } from '@/components/composites/Chart'

const revenueTrend = [
    { day: 1, value: 38 },
    { day: 2, value: 44 },
    { day: 3, value: 36 },
    { day: 4, value: 50 },
    { day: 5, value: 45 },
    { day: 6, value: 54 },
    { day: 7, value: 48 },
    { day: 8, value: 60 },
    { day: 9, value: 55 },
    { day: 10, value: 64 },
]

const MetricCardTrendWide = () => {
    return (
        <Card className="mx-auto w-full max-w-sm overflow-hidden" bodyClass="p-0">
            <div className="p-4">
                <p>Net Sales</p>
                <h4 className="mt-4 text-xl font-semibold">$84,200</h4>
                <div className="mt-1 flex items-center gap-1">
                    <GrowShrinkTag
                        value={12.4}
                        suffix="%"
                        prefix="+"
                        className="gap-1 border-0 bg-transparent p-0 text-sm font-semibold"
                    />
                    <span className="text-sm text-muted-foreground">month over month</span>
                </div>
            </div>
            <AreaChart
                data={revenueTrend}
                height={80}
                chartHorizontalSpace={0}
                chartVerticalSpace={0}
                xAxisConfig={{ dataKey: 'day', hide: true }}
                yAxisConfig={{ domain: ['dataMin - 10', 'dataMax + 5'] }}
                cartesianGridConfig={{ horizontal: false, vertical: false }}
                areaConfig={[
                    {
                        dataKey: 'value',
                        name: 'Sales',
                        stroke: 'var(--color-success)',
                        fill: 'url(#metricCardTrendWideFill)',
                        strokeWidth: 2,
                    },
                ]}
            >
                <defs>
                    <linearGradient id="metricCardTrendWideFill" x1="0" y1="0" x2="0" y2="1">
                        <stop offset="5%" stopColor="var(--color-success)" stopOpacity={0.35} />
                        <stop offset="95%" stopColor="var(--color-success)" stopOpacity={0} />
                    </linearGradient>
                </defs>
            </AreaChart>
        </Card>
    )
}

export default MetricCardTrendWide

Metric Card 05

Preview
npx nateui@latest add MetricCardStatsSummary
Dark
import StatisticCard from '@/components/composites/StatisticCard'
import Button from '@/components/ui/Button'
import Tooltip from '@/components/ui/Tooltip'
import GrowShrinkTag from '@/components/composites/GrowShrinkTag'
import { PiFileText, PiInfo, PiLink } from 'react-icons/pi'

const MetricCardStatsSummary = () => {
    return (
        <StatisticCard
            inset
            className="mx-auto w-full max-w-md"
            footer={
                <div className="grid grid-cols-1 gap-2 p-2 sm:grid-cols-2">
                    <div className="flex items-center gap-2">
                        <PiFileText className="text-base" />
                        <span>Tracked Keywords: 812</span>
                    </div>
                    <div className="flex items-center gap-2">
                        <PiLink className="text-base" />
                        <span>Indexed Pages: 96</span>
                    </div>
                </div>
            }
        >
            <div className="flex items-center gap-1.5">
                <h6 className="text-base font-medium">Search Visibility</h6>
                <Tooltip title="Summary of your organic search visibility for the selected period.">
                    <Button
                        variant="ghost"
                        shape="circle"
                        size="sm"
                        icon={<PiInfo />}
                        aria-label="About search visibility"
                    />
                </Tooltip>
            </div>

            <div className="mt-4 grid grid-cols-1 gap-4 sm:grid-cols-2">
                <div>
                    <p>Impression Share</p>
                    <div className="mt-1 flex items-baseline gap-2">
                        <h4 className="text-xl font-semibold">5.2K</h4>
                        <GrowShrinkTag 
                            value={5.4} 
                            suffix="%"
                            className="bg-card border"
                        />
                    </div>
                    <p className="mt-1 text-xs text-muted-foreground font-medium">Rank #14 of 300</p>
                </div>
                <div>
                    <p>Avg. Position</p>
                    <div className="mt-1 flex items-baseline gap-2">
                        <h4 className="text-xl font-semibold">2.4</h4>
                        <GrowShrinkTag 
                            value={2.6} 
                            suffix="%"
                            className="bg-card border" 
                        />
                    </div>
                    <p className="mt-1 text-xs text-muted-foreground font-medium">Rank #8 of 300</p>
                </div>
            </div>
        </StatisticCard>
    )
}

export default MetricCardStatsSummary

Metric Card 06

Preview
npx nateui@latest add MetricCardIconValue
Dark
import Card from '@/components/ui/Card'
import IconFrame from '@/components/composites/IconFrame'
import { PiWallet } from 'react-icons/pi'

const MetricCardIconValue = () => {
    return (
        <Card className="mx-auto w-full max-w-sm">
            <div className="flex items-start justify-between gap-4">
                <span>Payout Balance</span>
                <IconFrame className="border-0 bg-palette-purple-soft text-palette-purple-soft-foreground">
                    <PiWallet className="text-xl" />
                </IconFrame>
            </div>

            <h4 className="mt-4 text-xl font-semibold">
                $3,982.00
            </h4>

            <p className="text-sm text-muted-foreground">Previous month: $3,410.00</p>
        </Card>
    )
}

export default MetricCardIconValue

Metric Card 07

Preview
npx nateui@latest add MetricCardTargetSummary
Dark
import Card from '@/components/ui/Card'
import Progress from '@/components/ui/Progress'
import IconFrame from '@/components/composites/IconFrame'
import Divider from '@/components/composites/Divider'
import GrowShrinkTag from '@/components/composites/GrowShrinkTag'
import { PiCurrencyCircleDollar } from 'react-icons/pi'

const summaryRows = [
    { label: 'Profit margin', value: '39.6%' },
    { label: 'Subscription revenue', value: '$1.94M' },
    { label: 'Median deal size', value: '$28.6K' },
]

const MetricCardTargetSummary = () => {
    return (
        <Card className="mx-auto w-full max-w-sm" bodyClass="p-0">
            <div className="p-4">
                <div className="flex items-center gap-2">
                    <IconFrame size={48}>
                        <PiCurrencyCircleDollar className="text-2xl" />
                    </IconFrame>
                    <div>
                        <h6 className="text-base font-semibold">Net Revenue</h6>
                        <p className="text-muted-foreground">Q2 2026</p>
                    </div>
                </div>
                <div className="mt-8 flex items-center gap-2">
                    <h4 className="text-xl font-semibold">$3.18M</h4>
                    <GrowShrinkTag value={9.8} suffix="%" />
                </div>
                <div className="mt-2 flex items-center justify-between gap-4 text-sm">
                    <span>Quarterly goal: $3.6M</span>
                    <span className="font-semibold">88%</span>
                </div>
                <Progress
                    className="mt-2"
                    percent={88}
                    showInfo={false}
                />
            </div>

            <Divider className="my-0" />

            <div className="space-y-2 p-4">
                {summaryRows.map((row) => (
                    <div key={row.label} className="flex items-center justify-between gap-4">
                        <span>{row.label}</span>
                        <span className="font-semibold">{row.value}</span>
                    </div>
                ))}
            </div>
        </Card>
    )
}

export default MetricCardTargetSummary

Metric Card 08

Preview
npx nateui@latest add MetricCardChannelBreakdown
Dark
import StatisticCard from '@/components/composites/StatisticCard'
import IconFrame from '@/components/composites/IconFrame'
import { PiCursorClickFill } from 'react-icons/pi'

const channelRows = [
    { label: 'Newsletter', value: '6%' },
    { label: 'Push notifications', value: '22%' },
    { label: 'SMS alerts', value: '9%' },
]

const MetricCardChannelBreakdown = () => {
    return (
        <StatisticCard
            inset
            className="mx-auto w-full max-w-sm"
            header={
                <div className="flex items-center gap-2 -ml-2 py-0.5">
                    <IconFrame
                        size={28}
                        className="border-0 bg-palette-orange text-white"
                    >
                        <PiCursorClickFill />
                    </IconFrame>
                    <span className="font-medium">Engagements</span>
                </div>
            }
        >
            <div className="flex items-baseline justify-between gap-4">
                <h4 className="text-xl font-semibold">18%</h4>
                <span className="text-sm font-semibold text-destructive">-2.85%</span>
            </div>

            <div className="mt-4 space-y-2">
                {channelRows.map((row) => (
                    <div key={row.label} className="flex items-center justify-between gap-4 text-sm">
                        <span className="text-muted-foreground">{row.label}</span>
                        <span className="font-medium">{row.value}</span>
                    </div>
                ))}
            </div>
        </StatisticCard>
    )
}

export default MetricCardChannelBreakdown

Metric Card 09

Preview
npx nateui@latest add MetricCardInsight
Dark
import { useState } from 'react'
import Card from '@/components/ui/Card'
import Button from '@/components/ui/Button'
import Dropdown from '@/components/ui/Dropdown'
import { PiArrowUpRight, PiCaretDown, PiSparkle } from 'react-icons/pi'

const periodOptions = ['This week', 'This month', 'This quarter']

const MetricCardInsight = () => {
    const [period, setPeriod] = useState<string>(periodOptions[0])

    return (
        <Card className="relative mx-auto w-full max-w-sm overflow-hidden">
            <div className="relative">
                <div className="flex items-center justify-between gap-4">
                    <div className="flex items-center gap-2">
                        <PiSparkle className="text-lg" />
                        <span className="font-medium">Insight</span>
                    </div>
                    <Dropdown
                        placement="bottom-end"
                        activeKey={period}
                        onSelect={(eventKey) => setPeriod(eventKey)}
                        menuClass="min-w-40"
                        renderTitle={
                            <Button
                                variant="default"
                                size="sm"
                                icon={<PiCaretDown />}
                                iconAlignment="end"
                            >
                                {period}
                            </Button>
                        }
                    >
                        {periodOptions.map((option) => (
                            <Dropdown.Item key={option} eventKey={option}>
                                {option}
                            </Dropdown.Item>
                        ))}
                    </Dropdown>
                </div>

                <div className="mt-4 flex items-start gap-2">
                    <h4 className="text-xl font-semibold">92%</h4>
                    <PiArrowUpRight className="text-xl text-success" />
                </div>

                <p className="mt-4">
                    Your engagement is <span className="font-semibold">trending upward</span>{' '}
                    this week.
                </p>

                <p className="mt-2 text-sm text-muted-foreground">
                    Active users are following a similar pattern to last week, with steady
                    day-over-day growth across most channels.
                </p>
            </div>
        </Card>
    )
}

export default MetricCardInsight

Metric Card 10

Preview
npx nateui@latest add MetricCardStatusBreakdown
Dark
import Card from '@/components/ui/Card'
import GrowShrinkTag from '@/components/composites/GrowShrinkTag'

const breakdown = [
    { label: 'To Do', value: 40, colorClass: 'bg-palette-cyan' },
    { label: 'In Progress', value: 30, colorClass: 'bg-palette-blue' },
    { label: 'In Review', value: 20, colorClass: 'bg-palette-purple' },
    { label: 'Completed', value: 10, colorClass: 'bg-palette-rose' },
]

const MetricCardStatusBreakdown = () => {
    return (
        <Card className="mx-auto w-full max-w-md">
            <p className="text-sm text-muted-foreground">Tickets</p>

            <div className="mt-1 flex items-center gap-2">
                <h4 className="text-xl font-semibold">18,240</h4>
                <GrowShrinkTag value={21.6} suffix="%" />
            </div>

            <div className="mt-6 flex h-2 gap-0.5">
                {breakdown.map((segment) => (
                    <div
                        key={segment.label}
                        className={`h-full rounded-full ${segment.colorClass}`}
                        style={{ width: `${segment.value}%` }}
                    />
                ))}
            </div>

            <div className="mt-4 grid grid-cols-2 gap-4 sm:grid-cols-4">
                {breakdown.map((segment) => (
                    <div key={segment.label}>
                        <p className="text-sm text-muted-foreground">{segment.label}</p>
                        <div className="mt-1 flex items-center gap-1.5">
                            <span
                                className={`size-2 shrink-0 rounded-full ${segment.colorClass}`}
                            />
                            <span className="font-semibold">{segment.value}%</span>
                        </div>
                    </div>
                ))}
            </div>
        </Card>
    )
}

export default MetricCardStatusBreakdown

Metric Card 11

Preview
npx nateui@latest add MetricCardKpiStrip
Dark
import Card from '@/components/ui/Card'
import Tooltip from '@/components/ui/Tooltip'
import { AreaChart } from '@/components/composites/Chart'
import {
    PiArrowDown,
    PiArrowUp,
    PiCurrencyCircleDollar,
    PiHexagon,
    PiInfo,
    PiSparkle,
    PiUsers,
} from 'react-icons/pi'
import type { ComponentType, SVGProps } from 'react'

type Panel = {
    label: string
    chartName: string
    tooltip: string
    icon: ComponentType<SVGProps<SVGSVGElement>>
    value: string
    trend: 'up' | 'down'
    data: Array<{ x: number; value: number }>
}

const panels: Panel[] = [
    {
        label: 'Active Customers',
        chartName: 'Customers',
        tooltip: 'Total number of active customer accounts.',
        icon: PiUsers,
        value: '1,204',
        trend: 'up',
        data: [40, 45, 42, 50, 55, 52, 60].map((value, x) => ({ x, value })),
    },
    {
        label: 'New Signups',
        chartName: 'Signups',
        tooltip: 'New customer signups this period.',
        icon: PiSparkle,
        value: '98',
        trend: 'down',
        data: [50, 45, 52, 48, 53, 47, 50].map((value, x) => ({ x, value })),
    },
    {
        label: 'Sales Revenue',
        chartName: 'Revenue',
        tooltip: 'Total revenue generated from orders.',
        icon: PiCurrencyCircleDollar,
        value: '$22,150',
        trend: 'up',
        data: [30, 35, 40, 42, 48, 52, 58].map((value, x) => ({ x, value })),
    },
    {
        label: 'Affiliate Leads',
        chartName: 'Leads',
        tooltip: 'Leads generated through affiliate referrals.',
        icon: PiHexagon,
        value: '47',
        trend: 'up',
        data: [45, 50, 42, 48, 44, 50, 46].map((value, x) => ({ x, value })),
    },
]

const MetricCardKpiStrip = () => {
    return (
        <Card className="w-full" bodyClass="p-0">
            <div className="grid grid-cols-1 divide-y md:grid-cols-4 md:divide-x md:divide-y-0">
                {panels.map((panel) => {
                    const Icon = panel.icon
                    const TrendIcon = panel.trend === 'up' ? PiArrowUp : PiArrowDown
                    const gradientId = `metricCardKpiStripFill-${panel.label.replace(/\s+/g, '')}`

                    return (
                        <div key={panel.label} className="p-4">
                            <div className="flex items-center gap-1.5">
                                <Icon className="text-base" />
                                <span className="font-medium">{panel.label}</span>
                                <Tooltip
                                    title={panel.tooltip}
                                    tabIndex={0}
                                    aria-label={`About ${panel.label}`}
                                >
                                    <PiInfo className="text-muted-foreground" />
                                </Tooltip>
                            </div>

                            <div className="mt-3 flex items-center justify-between gap-2">
                                <div className="flex items-center gap-1">
                                    <span className="text-lg font-semibold">{panel.value}</span>
                                    <TrendIcon
                                        className={
                                            panel.trend === 'up'
                                                ? 'text-success'
                                                : 'text-destructive'
                                        }
                                    />
                                </div>
                                <div className="h-10 w-16 shrink-0">
                                    <AreaChart
                                        data={panel.data}
                                        height={40}
                                        chartHorizontalSpace={0}
                                        chartVerticalSpace={2}
                                        xAxisConfig={{ dataKey: 'x', hide: true }}
                                        yAxisConfig={{ domain: ['dataMin - 5', 'dataMax + 5'] }}
                                        cartesianGridConfig={{ horizontal: false, vertical: false }}
                                        areaConfig={[
                                            {
                                                dataKey: 'value',
                                                name: panel.chartName,
                                                stroke: 'var(--color-chart-1)',
                                                fill: `url(#${gradientId})`,
                                                strokeWidth: 1.5,
                                            },
                                        ]}
                                    >
                                        <defs>
                                            <linearGradient
                                                id={gradientId}
                                                x1="0"
                                                y1="0"
                                                x2="0"
                                                y2="1"
                                            >
                                                <stop
                                                    offset="5%"
                                                    stopColor="var(--color-chart-1)"
                                                    stopOpacity={0.3}
                                                />
                                                <stop
                                                    offset="95%"
                                                    stopColor="var(--color-chart-1)"
                                                    stopOpacity={0}
                                                />
                                            </linearGradient>
                                        </defs>
                                    </AreaChart>
                                </div>
                            </div>
                        </div>
                    )
                })}
            </div>
        </Card>
    )
}

export default MetricCardKpiStrip

Metric Card 12

Preview
npx nateui@latest add MetricCardKpiGrid
Dark
import Card from '@/components/ui/Card'
import IconFrame from '@/components/composites/IconFrame'
import GrowShrinkTag from '@/components/composites/GrowShrinkTag'
import {
    PiChartBar,
    PiCurrencyDollar,
    PiPackage,
    PiShoppingCartSimple,
} from 'react-icons/pi'
import type { ComponentType, SVGProps } from 'react'

type Metric = {
    label: string
    icon: ComponentType<SVGProps<SVGSVGElement>>
    iconClass: string
    value: string
    delta: { prefix: string; value: number; suffix: string }
}

const metrics: Metric[] = [
    {
        label: 'Gross Revenue',
        icon: PiCurrencyDollar,
        iconClass: 'bg-palette-orange',
        value: '$312.8K',
        delta: { prefix: '+$', value: 18.4, suffix: 'K' },
    },
    {
        label: 'Units Shipped',
        icon: PiPackage,
        iconClass: 'bg-palette-blue',
        value: '9,540',
        delta: { prefix: '+', value: 820, suffix: '' },
    },
    {
        label: 'Orders Placed',
        icon: PiShoppingCartSimple,
        iconClass: 'bg-palette-emerald',
        value: '6,180',
        delta: { prefix: '+', value: 512, suffix: '' },
    },
    {
        label: 'Signup Rate',
        icon: PiChartBar,
        iconClass: 'bg-palette-purple',
        value: '3.92%',
        delta: { prefix: '+', value: 0.18, suffix: '%' },
    },
]

const MetricCardKpiGrid = () => {
    return (
        <div className="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-4">
            {metrics.map((metric) => {
                const Icon = metric.icon

                return (
                    <Card key={metric.label}>
                        <div className="flex items-center gap-2">
                            <IconFrame size={32} className={`border-0 text-white ${metric.iconClass}`}>
                                <Icon className="text-lg" />
                            </IconFrame>
                            <span className="font-medium">{metric.label}</span>
                        </div>

                        <h4 className="mt-4 text-xl font-semibold">{metric.value}</h4>

                        <div className="mt-2 flex items-center gap-1 text-sm">
                            <GrowShrinkTag
                                prefix={metric.delta.prefix}
                                value={metric.delta.value}
                                suffix={metric.delta.suffix}
                                className="gap-1 border-0 bg-transparent p-0 font-semibold"
                            />
                            <span className="text-muted-foreground">vs previous month</span>
                        </div>
                    </Card>
                )
            })}
        </div>
    )
}

export default MetricCardKpiGrid