MetricCard
neon-ui/metric-cardFreeComponent
Analytics card with a formatted value, signed delta, and interactive Visx sparkline.
Install it
npx shadcn@latest add https://ui.neon.com/r/metric-card.jsonSource
1"use client";23import {4 Alert02Icon,5 MinusSignIcon,6 TradeDownIcon,7 TradeUpIcon,8} from "@hugeicons/core-free-icons";9import { HugeiconsIcon } from "@hugeicons/react";10import { useId } from "react";11import type { ComponentProps, ReactNode } from "react";12import { Area, AreaChart, XAxis, YAxis } from "recharts";1314import { NeonLoader } from "@/components/neon-loader/neon-loader";15import { Badge } from "@/components/ui/badge";16import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";17import type { ChartConfig } from "@/components/ui/chart";18import {19 ChartContainer,20 ChartTooltip,21 ChartTooltipContent,22} from "@/components/ui/chart";23import { Skeleton } from "@/components/ui/skeleton";24import { cn } from "@/lib/utils";2526export type MetricFormat =27 | "number"28 | "bytes"29 | "percent"30 | "currency"31 | "duration";3233export interface MetricTrendPoint {34 label: string;35 value: number;36}3738const NUMBER_FORMAT = new Intl.NumberFormat("en-US");39const CURRENCY_FORMAT = new Intl.NumberFormat("en-US", {40 currency: "USD",41 style: "currency",42});43const BYTE_UNITS = ["B", "KB", "MB", "GB", "TB", "PB"] as const;44const BYTE_STEP = 1024;45const SECONDS_PER_MINUTE = 60;46const SECONDS_PER_HOUR = 3600;4748const formatBytes = (bytes: number) => {49 if (bytes === 0) {50 return "0 B";51 }5253 const exponent = Math.min(54 Math.floor(Math.log(Math.abs(bytes)) / Math.log(BYTE_STEP)),55 BYTE_UNITS.length - 156 );57 const value = bytes / BYTE_STEP ** exponent;5859 return `${value.toFixed(value >= 100 || exponent === 0 ? 0 : 1)} ${BYTE_UNITS[exponent]}`;60};6162const formatDuration = (seconds: number) => {63 if (seconds < SECONDS_PER_MINUTE) {64 return `${Math.round(seconds)}s`;65 }66 if (seconds < SECONDS_PER_HOUR) {67 return `${Math.floor(seconds / SECONDS_PER_MINUTE)}m ${Math.round(seconds % SECONDS_PER_MINUTE)}s`;68 }6970 return `${Math.floor(seconds / SECONDS_PER_HOUR)}h ${Math.floor((seconds % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE)}m`;71};7273const formatValue = (value: number | string, format: MetricFormat) => {74 if (typeof value === "string") {75 return value;76 }7778 switch (format) {79 case "bytes": {80 return formatBytes(value);81 }82 case "percent": {83 return `${NUMBER_FORMAT.format(value)}%`;84 }85 case "currency": {86 return CURRENCY_FORMAT.format(value);87 }88 case "duration": {89 return formatDuration(value);90 }91 default: {92 return NUMBER_FORMAT.format(value);93 }94 }95};9697// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from neon-ui
All 77 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| ActivityFeedactivity-feed | neon-ui | Components | Free | 2 deps | |
| AgentChatagent-chat | neon-ui | Components | Free | 6 deps | |
| AnimatedWashanimated-wash | neon-ui | Components | Free | no deps · 2 files | |
| ApiKeyListapi-key-list | neon-ui | Components | Free | 2 deps | |
| AppCardapp-card | neon-ui | Components | Free | 2 deps | |
| AppCreatorapp-creator | neon-ui | Components | Free | 2 deps | |
| AuthFormauth-form | neon-ui | Components | Free | no deps | |
| AutoscaleChartautoscale-chart | neon-ui | Components | Free | 1 dep |
