← Components/Dashboard & App UI

KPICards

kpicards-1779379195514.tsx
'use client'
import { useState, useEffect, useRef } from 'react'

const METRICS = [
  { label: 'Monthly Revenue', value: 48320, prev: 41200, prefix: '$', suffix: '', color: '#C9A84C', data: [22,28,24,32,28,38,35,42,40,48] },
  { label: 'Active Users', value: 12847, prev: 10230, prefix: '', suffix: '', color: '#6366f1', data: [60,72,68,80,76,88,84,95,90,100] },
  { label: 'Conversion Rate', value: 3.42, prev: 2.91, prefix: '', suffix: '%', color: '#22c55e', data: [2.1,2.4,2.2,2.8,2.6,3.0,2.9,3.2,3.1,3.4] },
  { label: 'Churn Rate', value: 1.2, prev: 1.8, prefix: '', suffix: '%', color: '#ef4444', data: [2.4,2.1,2.3,1.9,2.1,1.8,1.7,1.5,1.3,1.2], invert: true },
]

function Sparkline({ data, color }: { data: number[]; color: string }) {
  const max = Math.max(...data), min = Math.min(...data)
  const W = 80, H = 32
  const points = data.map((v, i) => [i / (data.length - 1) * W, H - (v - min) / (max - min + 0.01) * H] as [number,number])
  const path = points.map((p, i) => `${i === 0 ? 'M' : 'L'}${p[0]},${p[1]}`).join(' ')
  const area = path + ` L${W},${H} L0,${H} Z`
  return (
    <svg width={W} height={H} viewBox={`0 0 ${W} ${H}`}>
      <path d={area} fill={color + '18'} />
      <path d={path} fill="none" stroke={color} strokeWidth={1.5} strokeLinecap="round" />
    </svg>
  )
}

function CountUp({ target, prefix, suffix }: { target: number; prefix: string; suffix: string }) {
  const [v, setV] = useState(0)
  useEffect(() => {
    const start = Date.now()
    const dur = 1200
    const tick = () => {
      const p = Math.min((Date.now() - start) / dur, 1)
      setV(target * (1 - Math.pow(1 - p, 3)))
      if (p < 1) requestAnimationFrame(tick)
    }
    requestAnimationFrame(tick)
  }, [target])
  const fmt = target < 10 ? v.toFixed(2) : target < 1000 ? Math.round(v).toLocaleString() : Math.round(v).toLocaleString()
  return <span>{prefix}{fmt}{suffix}</span>
}

export default function KPICards() {
  return (
    <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2,1fr)', gap: 12, padding: 24, background: '#080808' }}>
      {METRICS.map(m => {
        const pct = ((m.value - m.prev) / m.prev * 100).toFixed(1)
        const up = m.value > m.prev
        const good = m.invert ? !up : up
        return (
          <div key={m.label} style={{ background: '#0F0F0F', border: '1px solid rgba(255,255,255,0.06)', borderRadius: 14, padding: 20 }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: 12 }}>
              <span style={{ color: 'rgba(255,255,255,0.45)', fontSize: 12, fontWeight: 500 }}>{m.label}</span>
              <Sparkline data={m.data} color={m.color} />
            </div>
            <div style={{ color: '#F5F5F0', fontSize: 26, fontWeight: 800, letterSpacing: '-0.02em', marginBottom: 8 }}>
              <CountUp target={m.value} prefix={m.prefix} suffix={m.suffix} />
            </div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
              <span style={{ color: good ? '#22c55e' : '#ef4444', fontSize: 12, fontWeight: 600, background: (good ? '#22c55e' : '#ef4444') + '18', padding: '2px 6px', borderRadius: 4 }}>
                {up ? '↑' : '↓'} {Math.abs(Number(pct))}%
              </span>
              <span style={{ color: 'rgba(255,255,255,0.3)', fontSize: 12 }}>vs last month</span>
            </div>
          </div>
        )
      })}
    </div>
  )
}

Component info

CategoryDashboard & App UI
Frameworkreact
TierFREE
Views0
Copies0

About

4 KPI metric cards with trend sparklines, comparison to last period, and animated count-up

More from Dashboard & App UI

import React from 'react';

interface MetricCardProps {
  value: number;
  trend: 'up' | 'down';
  sparklineData: number[];
}

const MetricCard: React.FC<MetricCardProps> = ({ value, trend, sparklineData }) => {
  return (
    <div style={{ backgroun
MetricCard
Dashboard & App UI
import React from 'react';
import './ProgressRing.css';
interface ProgressRingProps {
  percentage: number;
}
const ProgressRing: React.FC<ProgressRingProps> = ({ percentage }) => {
  const circleDashArray = 2 * Math.PI * 50;
  const circleDashOffset
ProgressRing
Dashboard & App UI
'use client';

import React from 'react';

interface KPIWidgetProps {
  metric: number;
  label: string;
  target: number;
  progress: number;
  sparklineData: number[];
  periodComparison: string;
}

const KPIWidget: React.FC<KPIWidgetProps> = ({
  
KPIWidget
Dashboard & App UI
'use client'
import { useState, useEffect } from 'react'

type EventType = 'component_added' | 'user_signup' | 'purchase' | 'api_call' | 'review'

const EVENTS: { id: number; type: EventType; user: string; detail: string; time: number; color: string;
ActivityFeed
Dashboard & App UI