Activity
Web traffic
2.4M
12%
Total bandwidth
1.8TB
9%
Cache rate
92.1%
3.2%
Client errors
4.8k
8%
import { MetricCard, MetricCardGroup } from "@cloudflare/kumo";

export function MetricCardGroupDemo() {
return (
  <MetricCardGroup title="Activity">
    <MetricCard
      label="Web traffic"
      value="2.4M"
      trend={{ direction: "up", label: "12%" }}
      sparkline={{
        data: [
          1.69, 1.62, 1.79, 1.98, 1.99, 1.89, 1.9, 2.07, 2.16, 2.04, 1.87,
          1.91, 2.14, 2.3, 2.23, 2.13, 2.19, 2.34, 2.36, 2.21, 2.11, 2.26,
          2.5, 2.58,
        ],
      }}
    />
    <MetricCard
      label="Total bandwidth"
      value="1.8"
      unit="TB"
      trend={{ direction: "up", label: "9%" }}
      sparkline={{
        data: [
          1.25, 1.29, 1.24, 1.24, 1.34, 1.42, 1.38, 1.28, 1.3, 1.44, 1.55,
          1.54, 1.48, 1.51, 1.61, 1.65, 1.58, 1.53, 1.6, 1.76, 1.83, 1.78,
          1.72, 1.77,
        ],
      }}
    />
    <MetricCard
      label="Cache rate"
      value="92.1"
      unit="%"
      trend={{ direction: "up", label: "3.2%" }}
    />
    <MetricCard
      label="Client errors"
      value="4.8k"
      trend={{ direction: "down", label: "8%", lessIsBetter: true }}
    />
  </MetricCardGroup>
);
}

Installation

Barrel

import { MetricCard, MetricCardGroup } from "@cloudflare/kumo";

Granular

import { MetricCard } from "@cloudflare/kumo/components/metric-card";
import { MetricCardGroup } from "@cloudflare/kumo/components/metric-card-group";

Usage

import { MetricCard, MetricCardGroup } from "@cloudflare/kumo";

export default function Example() {
  return (
    <MetricCardGroup title="Overview">
      <MetricCard label="Requests" value="1.2M" />
      <MetricCard label="Error Rate" value="0.3" unit="%" />
    </MetricCardGroup>
  );
}

Examples

Horizontal Group

The default layout arranges metric cards in a horizontal row with vertical dividers.

Performance
CPU time P90
3.2ms
8%
Workers errors
0
0.0%
Workers invocations
1.2M
12%
import { MetricCard, MetricCardGroup } from "@cloudflare/kumo";

export function MetricCardHorizontalGroupDemo() {
return (
  <MetricCardGroup title="Performance">
    <MetricCard
      label="CPU time P90"
      value="3.2"
      unit="ms"
      trend={{ direction: "down", label: "8%", lessIsBetter: true }}
      sparkline={{
        data: [
          3.91, 4.36, 4.41, 4.02, 3.74, 3.88, 4.08, 3.87, 3.44, 3.36,
          3.77, 4.12, 3.94, 3.47, 3.3, 3.52, 3.64, 3.36, 3.04, 3.16,
          3.61, 3.76, 3.37, 2.9,
        ],
      }}
    />
    <MetricCard
      label="Workers errors"
      value="0"
      trend={{ direction: "neutral", label: "0.0%", isNeutral: true }}
      sparkline={{
        data: [0, 0],
        theme: "danger",
      }}
    />
    <MetricCard
      label="Workers invocations"
      value="1.2M"
      trend={{ direction: "up", label: "12%" }}
    />
  </MetricCardGroup>
);
}

Vertical Group

Use orientation="vertical" for sidebar or narrow container layouts.

Registrar
Active domains
142
Expiring soon
3
Pending transfers
2
import { MetricCard, MetricCardGroup } from "@cloudflare/kumo";

export function MetricCardGroupVerticalDemo() {
  return (
    <div className="max-w-sm mx-auto">
      <MetricCardGroup title="Registrar" orientation="vertical">
        <MetricCard label="Active domains" value="142" />
        <MetricCard label="Expiring soon" value="3" />
        <MetricCard label="Pending transfers" value="2" />
      </MetricCardGroup>
    </div>
  );
}

Without Title

Omit the title prop for a minimal layout without a header.

Web traffic
2.4M
Total bandwidth
842GB
Workers invocations
1.2M
import { MetricCard, MetricCardGroup } from "@cloudflare/kumo";

export function MetricCardGroupWithoutTitleDemo() {
return (
  <MetricCardGroup>
    <MetricCard
      label="Web traffic"
      value="2.4M"
      sparkline={{
        data: [
          1.86, 1.88, 1.75, 1.7, 1.88, 2.11, 2.14, 1.97, 1.88, 1.98,
          2.13, 2.11, 1.99, 2.02, 2.24, 2.41, 2.33, 2.14, 2.11, 2.27,
          2.4, 2.35, 2.26, 2.36,
        ],
      }}
    />
    <MetricCard
      label="Total bandwidth"
      value="842"
      unit="GB"
      sparkline={{
        data: [
          682.96, 643.68, 599.64, 616.3, 668.98, 685.79, 657.11, 649.29,
          702.63, 765.45, 763.99, 708.53, 681.15, 721.75, 776.34, 780.2,
          752.18, 762.21, 821.91, 861.85, 831.43, 775.95, 776.53, 838.01,
        ],
      }}
    />
    <MetricCard
      label="Workers invocations"
      value="1.2M"
    />
  </MetricCardGroup>
);
}

Sparklines

Add sparkline visualizations with themed or custom colors.

Performance
Cache rate
92.1%
3.2%
Client errors
4.8k
8%
CPU time P90
3.2ms
8%
Uptime
99.99%
0.0%
import { MetricCard, MetricCardGroup } from "@cloudflare/kumo";

export function MetricCardSparklineDemo() {
return (
  <MetricCardGroup title="Performance">
    <MetricCard
      label="Cache rate"
      value="92.1"
      unit="%"
      trend={{ direction: "up", label: "3.2%" }}
      sparkline={{
        data: [
          83.96, 88.56, 90.5, 87.29, 84.93, 88.62, 94.47, 94.59, 88.45,
          83.97, 86.51, 91.74, 92.37, 88.79, 88, 92.65, 96.59, 93.67,
          87.08, 85.28, 90.31, 95.21, 94.12, 90.4,
        ],
        theme: "success",
      }}
    />
    <MetricCard
      label="Client errors"
      value="4.8k"
      trend={{ direction: "down", label: "8%", lessIsBetter: true }}
      sparkline={{
        data: [
          6138.54, 5544.96, 5909.1, 6819.45, 6923.97, 5877.53, 4895.88,
          5081.88, 5925.52, 6120.88, 5470.26, 5090.26, 5657.14, 6317.94,
          5908.69, 4709.82, 4143.49, 4805.35, 5660.03, 5546.95, 4795.58,
          4623.79, 5256.64, 5567.25,
        ],
        theme: "danger",
      }}
    />
    <MetricCard
      label="CPU time P90"
      value="3.2"
      unit="ms"
      trend={{ direction: "down", label: "8%", lessIsBetter: true }}
      sparkline={{
        data: [
          4.4, 4.5, 4.08, 3.59, 3.58, 3.95, 4.1, 3.84, 3.6, 3.77, 4.07,
          3.96, 3.44, 3.1, 3.33, 3.73, 3.75, 3.41, 3.24, 3.47, 3.64,
          3.35, 2.86, 2.76,
        ],
        theme: "neutral",
      }}
    />
    <MetricCard
      label="Uptime"
      value="99.99"
      unit="%"
      trend={{ direction: "neutral", label: "0.0%", isNeutral: true }}
      sparkline={{
        data: [
          99.98, 99.98, 99.99, 99.99, 99.98, 99.99, 99.99, 99.99, 99.98,
          99.99, 99.99, 99.99, 99.99, 99.98, 99.99, 99.99, 99.99, 99.99,
          99.98, 99.99, 99.99, 99.99, 99.99, 99.99,
        ],
        yMin: 99.9,
      }}
    />
  </MetricCardGroup>
);
}

Interactive Cards

Cards become clickable when given an href or onClick prop. Use tooltip to add contextual information.

import { MetricCard, MetricCardGroup } from "@cloudflare/kumo";
import { QuestionIcon } from "@phosphor-icons/react";

export function MetricCardInteractiveDemo() {
  return (
    <MetricCardGroup title="Workers Overview">
      <MetricCard
        label="Workers invocations"
        value="1.2M"
        tooltip="Total invocations across all Workers"
        href="#"
      />
      <MetricCard
        label="CPU time P90"
        value="3.2"
        unit="ms"
        tooltip="90th percentile CPU time per invocation"
        tooltipIcon={QuestionIcon}
        href="#"
      />
      <MetricCard
        label="Workers errors"
        value="842"
        tooltip="Failed invocations returning non-2xx status"
        onClick={() => {}}
      />
    </MetricCardGroup>
  );
}

Loading and Error States

MetricCard supports loading and error states for async data.

Browser Rendering
Browser sessions
Browser hours
import { MetricCard, MetricCardGroup } from "@cloudflare/kumo";

export function MetricCardStatesDemo() {
  return (
    <MetricCardGroup title="Browser Rendering">
      <MetricCard label="Browser sessions" loading />
      <MetricCard label="Browser hours" error />
    </MetricCardGroup>
  );
}

Badge Values

Pass a ReactNode like Badge as the value prop for status indicators. ReactNode values render with their own styling. String values automatically receive metric typography.

System Status
API
Operational
Database
Degraded
Uptime
99.9%
import { MetricCard, MetricCardGroup, Badge } from "@cloudflare/kumo";

export function MetricCardBadgeValueDemo() {
  return (
    <MetricCardGroup title="System Status">
      <MetricCard
        label="API"
        value={<Badge variant="success">Operational</Badge>}
      />
      <MetricCard
        label="Database"
        value={<Badge variant="warning">Degraded</Badge>}
      />
      <MetricCard label="Uptime" value="99.9" unit="%" />
    </MetricCardGroup>
  );
}

API Reference

MetricCard

Compact card displaying a single metric value with optional trend, sparkline, and loading/error states.

PropTypeDefaultDescription
classNamestring--
idstring--
titlestring--
childrenReactNode--
label*string-Label text displayed above the value.
valuestring | ReactNode-Metric value to display. Strings and numbers receive automatic metric typography (text-xl, font-semibold, tabular-nums). ReactNode values like Badge render as-is. Optional when `loading` or `error` is true.
unitstring-Unit displayed after the value in smaller text, e.g. "%", "ms".
trendMetricCardTrend-Trend indicator with direction arrow and label.
sparklineMetricCardSparkline-Sparkline chart rendered at the bottom of the card.
hrefstring-When set, renders the card as an anchor element.
loadingboolean-Shows skeleton loading state for the value.
errorboolean-Shows an em-dash placeholder in place of the value.
tooltipReactNode-Content displayed in a tooltip next to the label.
tooltipIconReact.ComponentType<MetricCardTooltipIconProps>-Custom icon component for the tooltip trigger. Defaults to Info icon from Phosphor.
onClick(event: React.MouseEvent<HTMLElement>) => void-Click handler. Renders the card as a button when no `href` is provided.

The trend and sparkline props accept configuration objects described below.

Trend Options

Options for the trend prop.

PropTypeDefaultDescription
direction*"up" | "down" | "neutral"-Arrow direction: up (↑), down (↓), or neutral (→).
label*string-Pre-formatted trend label, e.g. "13.8%", "2.3pp", "5.1ms".
lessIsBetterbooleanfalseInverts color semantics: down becomes green (good), up becomes red (bad). Use for metrics like latency or error count.
isNeutralbooleanfalseForces neutral (gray) styling regardless of direction. Use for metrics where change has no good/bad meaning.

Sparkline Options

Options for the sparkline prop.

PropTypeDefaultDescription
data*number[]-Array of numeric data points to plot.
theme"success" | "danger" | "neutral"Brand colorPreset color theme for the sparkline. For custom colors beyond these presets, use the color prop instead.
colorstring-Custom color that overrides theme. Accepts any CSS color value including kumo tokens, e.g. "var(--color-kumo-brand)" or "#E87B35".
yMinnumberAuto from dataOverride the auto-scaled minimum y value.
yMaxnumberAuto from dataOverride the auto-scaled maximum y value.

MetricCardGroup

Groups MetricCard children inside a card with an optional header and configurable orientation.

PropTypeDefaultDescription
classNamestring--
idstring--
childrenReactNode-MetricCard children to render inside the group.
orientation"horizontal" | "vertical""horizontal"Layout direction for child metric cards. - `"horizontal"` — Cards in a row with vertical dividers - `"vertical"` — Cards stacked with horizontal dividers
titleReactNode-Optional header text rendered in a LayerCard.Secondary section.