Now with AI Insights — ask your dashboard questions

The last dashboard library
you'll ever install.

44 components. 18 chart types. AI-powered analysis. Cross-filtering. Drill-downs. Export. Stop assembling dashboards from parts — and let your dashboard explain itself.

npm install metricuiMIT · Open Source · Free
44
Components
18
Chart Types
686
Tests
5
Demos

Live Components

Real MetricUI components rendering below. Sparklines, comparisons, goals, conditional colors — no screenshots.

Revenue
$0
+12.3%vs last month
Active Users
0
+9.6%
Q4 Target(10K)84%
Conversion
0%
+14.3%

Superpowers

Not just charts.
A complete dashboard intelligence platform.

AI Insights

Your dashboard learned to talk.

Drop in one component. Connect your LLM. End users ask questions about their data — the AI sees every chart, every filter, every number. @ mention specific metrics. Get answers grounded in what's actually on screen.

Cross-Filtering

Click a bar. Everything responds.

Click a donut slice, a bar, a table row — every other component on the page filters to match. One prop: crossFilter. No wiring code. Click again to clear. Signal-only architecture — you own the data, we own the interaction.

Drill-Downs

Click any metric. See the detail.

drillDown={true} auto-generates a detail panel. Or pass a function for custom content. Slide-over or modal. Nested up to 4 levels with breadcrumbs. Works on every component — KPIs, charts, tables.

Export

PNG. CSV. Clipboard. One prop.

exportable on MetricProvider. Every component gets a download button. 4x DPI PNGs via modern-screenshot. CSV with filter metadata. Clean filenames. The finance team stops asking you for screenshots.

Before & After

65 lines of glue code?
Or 10 lines that do more?

One KPI card with formatting, comparison, sparkline, loading, error handling, dark mode, export, and AI context.

RevenueCard.tsx — 65 lines, still missing features
// The usual way — Recharts + shadcn + custom everything
import { AreaChart, Area, XAxis, YAxis, Tooltip, ResponsiveContainer } from "recharts";
import { Card, CardHeader, CardTitle, CardContent } from "@/ui/card";
import { Skeleton } from "@/ui/skeleton";
import { TrendingUp, TrendingDown } from "lucide-react";
import { cn } from "@/lib/utils";

function formatCurrency(n: number) {
  return new Intl.NumberFormat("en-US", {
    style: "currency", currency: "USD",
    minimumFractionDigits: 0, maximumFractionDigits: 0,
  }).format(n);
}

function RevenueCard({ value, prev, sparkline, loading, error }) {
  if (loading) return (
    <Card>
      <CardHeader><Skeleton className="h-4 w-24" /></CardHeader>
      <CardContent className="space-y-3">
        <Skeleton className="h-8 w-32" />
        <Skeleton className="h-4 w-20" />
        <Skeleton className="h-16 w-full" />
      </CardContent>
    </Card>
  );

  if (error) return (
    <Card>
      <CardContent className="py-8 text-center text-sm text-red-500">
        Failed to load — <button onClick={() => window.location.reload()}>Retry</button>
      </CardContent>
    </Card>
  );

  const change = prev !== 0 ? ((value - prev) / prev) * 100 : 0;
  const isPositive = change >= 0;
  const Icon = isPositive ? TrendingUp : TrendingDown;

  return (
    <Card>
      <CardHeader>
        <CardTitle className="text-xs font-medium text-muted-foreground uppercase">
          Revenue
        </CardTitle>
      </CardHeader>
      <CardContent>
        <p className="text-2xl font-bold">{formatCurrency(value)}</p>
        <div className={cn("flex items-center gap-1 text-sm mt-1",
          isPositive ? "text-green-600" : "text-red-600"
        )}>
          <Icon className="h-3 w-3" />
          <span>{isPositive ? "+" : ""}{change.toFixed(1)}% vs last month</span>
        </div>
        {sparkline && (
          <div className="mt-3 h-16">
            <ResponsiveContainer width="100%" height="100%">
              <AreaChart data={sparkline.map((v, i) => ({ i, v }))}>
                <Area type="monotone" dataKey="v" stroke="#6366f1"
                  fill="url(#grad)" strokeWidth={1.5} />
              </AreaChart>
            </ResponsiveContainer>
          </div>
        )}
      </CardContent>
    </Card>
  );
}

// 65 lines. Still missing: goal progress, conditional coloring,
// comparison badges, copy-to-clipboard, drill-down, dense mode,
// dark mode, null handling, count-up animation, export...

Quick Start

A complete AI-powered dashboard.
25 lines.

Dashboard wrapper, filters, cross-filtering, drill-downs, export, and AI chat — all configured.

app/dashboard/page.tsx
import { Dashboard, KpiCard, AreaChart, MetricGrid, DashboardInsight } from "metricui";
import "metricui/styles.css";

export default function MyDashboard() {
  return (
    <Dashboard
      theme="emerald"
      filters={{ defaultPreset: "30d" }}
      exportable
      ai={{ analyze: myLLM, company: "Acme Corp", context: "Q4 revenue dashboard" }}
    >
      <MetricGrid>
        <KpiCard title="Revenue" value={127450} format="currency"
          comparison={{ value: 113500 }}
          aiContext="Our north star metric. Enterprise drives 52%." />
        <KpiCard title="Users" value={8420} format="number"
          goal={{ value: 10000, showProgress: true }} />
        <AreaChart data={revenueData} index="month" categories={["revenue"]}
          title="Revenue Over Time" crossFilter drillDown />
      </MetricGrid>
      <DashboardInsight />
    </Dashboard>
  );
}

Everything Included

The features real dashboards need

One import, not six libraries

KPI cards, 18 chart types, tables, layout, formatting, theming — one package. No glue code.

Built-in data states

Loading skeletons, empty states, error retry, stale indicators. On every component. Pass a prop.

Complete filter system

FilterBar + PeriodSelector + DropdownFilter + SegmentToggle + FilterTags. All wired through context.

8 theme presets + dark mode

One prop changes everything. Indigo, emerald, rose, amber, cyan, violet, slate, orange. CSS variables.

Smart defaults, zero config

Auto column inference on tables. Auto-format from key names. MetricGrid auto-layout. It just works.

MCP server for AI tools

Claude, Cursor, Copilot generate correct MetricUI code on the first try. Full API surface exposed.

686 tests. TypeScript-first.

Every component tested. Every prop typed. BaseComponentProps inherited everywhere. Ship with confidence.

44 components. All free.

MIT license. No pro tier. No gates. KPIs, charts, tables, filters, layout, AI — everything ships.

Your next dashboard deserves better.

Stop assembling six libraries into a dashboard. Start building one that thinks.