Datenvisualisierung

Recharts mit Claude Code:
Datenvisualisierung für React 2026

LineChart, BarChart, AreaChart, PieChart, Custom Tooltips, Responsive Container — professionelle Dashboards mit KI-Unterstützung.

📅 5. Mai 2026 ⏱ 10 min Lesezeit 🏷 Datenvisualisierung

Recharts ist die meistgenutzte Chart-Library für React — und Claude Code macht sie noch leistungsstärker. Statt stundenlang Dokumentation zu durchsuchen generiert die KI vollständige, typsichere Chart-Komponenten auf Knopfdruck: responsive Layouts, animierte Übergänge, Custom Tooltips, komplexe Datenstrukturen. Dieser Guide zeigt alle sechs wichtigen Chart-Typen mit production-ready Code.

1. Recharts vs Chart.js vs D3 — Vergleich für React

Die Wahl der richtigen Chart-Library entscheidet über Entwicklungsgeschwindigkeit, Bundle-Größe und Flexibilität. Alle drei Optionen haben ihre Daseinsberechtigung — aber für React-Projekte ist die Entscheidung meist klar.

Kriterium Recharts Chart.js D3.js
React-Integration Nativ (SVG + JSX) Canvas, Wrapper nötig DOM-Manipulation
Lernkurve Flach Flach Steil
Bundle-Größe ~300 KB ~200 KB ~500 KB
Anpassbarkeit Hoch (Props + Custom) Mittel Maximal
TypeScript Vollständige Types Gut Partiell
Claude Code Support Exzellent Sehr gut Gut
Responsive ResponsiveContainer Built-in Manuell

Wann welche Library?

Installation und Claude Code Setup

Terminal bash
# Recharts installieren
npm install recharts
npm install -D @types/recharts # Falls nötig (meist automatisch)

# Claude Code starten
claude
# > "Erstelle ein Revenue-Dashboard mit Recharts: LineChart für Umsatz,
# BarChart für Kategorien, PieChart für Anteile — responsive, animiert"

Claude Code versteht Recharts-Konventionen vollständig — ResponsiveContainer, CartesianGrid, XAxis/YAxis, Tooltip, Legend. Ein einziger Prompt liefert eine vollständige, production-ready Dashboard-Komponente.

2. LineChart und AreaChart — Responsive, Multi-Series, Referenzlinie

LineChart

Einsatzgebiete

RevenueLineChart.tsx tsx
import { useMemo } from 'react';
import {
  LineChart, Line, XAxis, YAxis, CartesianGrid,
  Tooltip, Legend, ResponsiveContainer, ReferenceLine
} from 'recharts';

interface DataPoint {
  month: string;
  revenue: number;
  target: number;
  lastYear: number;
}

const data: DataPoint[] = [
  { month: 'Jan', revenue: 42000, target: 45000, lastYear: 38000 },
  { month: 'Feb', revenue: 48500, target: 45000, lastYear: 40200 },
  { month: 'Mär', revenue: 51200, target: 50000, lastYear: 43100 },
  { month: 'Apr', revenue: 49800, target: 50000, lastYear: 44500 },
  { month: 'Mai', revenue: 58300, target: 55000, lastYear: 46000 },
  { month: 'Jun', revenue: 63100, target: 55000, lastYear: 48800 },
];

export function RevenueLineChart() {
  const formatEuro = (v: number) => `€${(v/1000).toFixed(1)}k`;

  return (
    <ResponsiveContainer width="100%" height={320}>
      <LineChart data={data} margin={{ top: 8, right: 24, left: 8, bottom: 0 }}>
        <CartesianGrid strokeDasharray="3 3" stroke="#1e293b" />
        <XAxis dataKey="month" tick={{ fill: '#64748b', fontSize: 12 }} />
        <YAxis tickFormatter={formatEuro} tick={{ fill: '#64748b', fontSize: 12 }} />
        <Tooltip formatter={(v: number) => [formatEuro(v)]} />
        <Legend />
        <ReferenceLine y={55000} stroke="#f59e0b" strokeDasharray="4 4"
          label={{ value: 'Ziel H2', fill: '#f59e0b', fontSize: 11 }} />
        <Line type="monotone" dataKey="revenue" stroke="#6366f1"
          strokeWidth={2.5} dot={{ r: 4, fill: '#6366f1' }} name="Umsatz"
          animationDuration={800} />
        <Line type="monotone" dataKey="target" stroke="#f59e0b"
          strokeWidth={1.5} strokeDasharray="5 5" dot={false} name="Ziel" />
        <Line type="monotone" dataKey="lastYear" stroke="#475569"
          strokeWidth={1.5} dot={false} name="Vorjahr" />
      </LineChart>
    </ResponsiveContainer>
  );
}

AreaChart — Gradient Fill und Zoom

Der AreaChart eignet sich besonders für kumulierte Metriken wie Gesamtumsatz oder User-Wachstum. Mit einem SVG-Gradient und der defs-Unterstützung von Recharts entstehen visuell beeindruckende Charts.

GrowthAreaChart.tsx tsx
import {
  AreaChart, Area, XAxis, YAxis, CartesianGrid,
  Tooltip, ResponsiveContainer, defs, linearGradient, stop
} from 'recharts';

export function GrowthAreaChart({ data }: { data: DataPoint[] }) {
  return (
    <ResponsiveContainer width="100%" height={280}>
      <AreaChart data={data}>
        <defs>
          <linearGradient id="colorRevenue" x1="0" y1="0" x2="0" y2="1">
            <stop offset="5%" stopColor="#6366f1" stopOpacity={0.3} />
            <stop offset="95%" stopColor="#6366f1" stopOpacity={0} />
          </linearGradient>
        </defs>
        <CartesianGrid strokeDasharray="3 3" stroke="#1e293b" />
        <XAxis dataKey="month" tick={{ fill: '#64748b', fontSize: 12 }} />
        <YAxis tick={{ fill: '#64748b', fontSize: 12 }} />
        <Tooltip />
        <Area
          type="monotone"
          dataKey="revenue"
          stroke="#6366f1"
          strokeWidth={2}
          fill="url(#colorRevenue)"
          animationDuration={1000}
          animationEasing="ease-out"
        />
      </AreaChart>
    </ResponsiveContainer>
  );
}
Claude Code Prompt-Tipp:

"Füge meinem AreaChart einen Brush-Zoom-Selector am unteren Rand hinzu, sodass Nutzer einen Zeitraum auswählen können." — Claude Code fügt den <Brush>-Component mit korrekten Datenlinks in Sekunden ein.

3. BarChart und ComposedChart — Gruppiert, Gestapelt, Gemischt

BarChart

Drei Modi

CategoryBarChart.tsx — Gruppiert + Gestapelt tsx
import {
  BarChart, Bar, XAxis, YAxis, CartesianGrid,
  Tooltip, Legend, ResponsiveContainer, Cell
} from 'recharts';

const salesData = [
  { category: 'Software', q1: 24000, q2: 31000, q3: 28000 },
  { category: 'Services', q1: 18000, q2: 22000, q3: 25000 },
  { category: 'Hardware', q1: 12000, q2: 9500, q3: 11200 },
  { category: 'Training', q1: 8000, q2: 11000, q3: 13500 },
];

export function GroupedBarChart() {
  return (
    <ResponsiveContainer width="100%" height={300}>
      <BarChart data={salesData} barCategoryGap="20%" barGap={4}>
        <CartesianGrid strokeDasharray="3 3" stroke="#1e293b" vertical={false} />
        <XAxis dataKey="category" tick={{ fill: '#64748b', fontSize: 12 }} />
        <YAxis tickFormatter={v => `€${v/1000}k`} tick={{ fill: '#64748b', fontSize: 12 }} />
        <Tooltip formatter={(v: number) => [`€${v.toLocaleString()}`, '']} />
        <Legend />
        <Bar dataKey="q1" fill="#6366f1" radius={[4,4,0,0]} name="Q1" animationDuration={600} />
        <Bar dataKey="q2" fill="#8b5cf6" radius={[4,4,0,0]} name="Q2" animationDuration={800} />
        <Bar dataKey="q3" fill="#a78bfa" radius={[4,4,0,0]} name="Q3" animationDuration={1000} />
      </BarChart>
    </ResponsiveContainer>
  );
}

ComposedChart — Balken und Linie kombinieren

SalesComposedChart.tsx tsx
import {
  ComposedChart, Bar, Line, XAxis, YAxis,
  CartesianGrid, Tooltip, Legend, ResponsiveContainer
} from 'recharts';

const combined = [
  { month: 'Jan', umsatz: 42000, wachstum: 8.2 },
  { month: 'Feb', umsatz: 48500, wachstum: 15.5 },
  { month: 'Mär', umsatz: 51200, wachstum: 5.6 },
  { month: 'Apr', umsatz: 49800, wachstum: -2.7 },
  { month: 'Mai', umsatz: 58300, wachstum: 17.1 },
];

export function SalesComposedChart() {
  return (
    <ResponsiveContainer width="100%" height={300}>
      <ComposedChart data={combined}>
        <CartesianGrid strokeDasharray="3 3" stroke="#1e293b" />
        <XAxis dataKey="month" tick={{ fill: '#64748b' }} />
        <YAxis yAxisId="left" tickFormatter={v => `€${v/1000}k`} tick={{ fill: '#64748b' }} />
        <YAxis yAxisId="right" orientation="right" tickFormatter={v => `${v}%`} tick={{ fill: '#64748b' }} />
        <Tooltip />
        <Legend />
        <Bar yAxisId="left" dataKey="umsatz" fill="#6366f1" radius={[4,4,0,0]} name="Umsatz" />
        <Line yAxisId="right" type="monotone" dataKey="wachstum"
          stroke="#10b981" strokeWidth={2} dot={{ r: 5 }} name="Wachstum %" />
      </ComposedChart>
    </ResponsiveContainer>
  );
}

Der ComposedChart mit zwei Y-Achsen (yAxisId="left" und yAxisId="right") ist ein häufiges Pattern in Business-Dashboards. Claude Code generiert die korrekte Doppel-Achsen-Konfiguration mit einem einzigen Prompt automatisch.

4. PieChart und RadialBarChart — Labels, Custom Cells, Active Shape

PieChart

Anwendungsfälle

MarketSharePie.tsx — Active Shape Pattern tsx
import { useState, useCallback } from 'react';
import { PieChart, Pie, Cell, Sector, ResponsiveContainer, Tooltip } from 'recharts';

const COLORS = ['#6366f1', '#8b5cf6', '#a78bfa', '#c4b5fd', '#10b981'];

const marketData = [
  { name: 'Enterprise', value: 38 },
  { name: 'Mid-Market', value: 27 },
  { name: 'SMB', value: 19 },
  { name: 'Startup', value: 11 },
  { name: 'Sonstige', value: 5 },
];

// Active Shape: animierter erweiterter Sektor bei Hover
const renderActiveShape = (props: any) => {
  const { cx, cy, innerRadius, outerRadius, startAngle, endAngle,
    fill, payload, percent, value } = props;
  return (
    <g>
      <text x={cx} y={cy - 8} textAnchor="middle" fill="#f1f5f9" fontSize=14 fontWeight=700>
        {payload.name}
      </text>
      <text x={cx} y={cy + 12} textAnchor="middle" fill="#94a3b8" fontSize=12>
        {value}% • {(percent * 100).toFixed(1)}%
      </text>
      <Sector cx={cx} cy={cy} innerRadius={innerRadius} outerRadius={outerRadius + 8}
        startAngle={startAngle} endAngle={endAngle} fill={fill} />
      <Sector cx={cx} cy={cy} innerRadius={outerRadius + 12} outerRadius={outerRadius + 16}
        startAngle={startAngle} endAngle={endAngle} fill={fill} />
    </g>
  );
};

export function MarketSharePie() {
  const [activeIndex, setActiveIndex] = useState(0);
  const onPieEnter = useCallback((_: any, index: number) => {
    setActiveIndex(index);
  }, []);

  return (
    <ResponsiveContainer width="100%" height={320}>
      <PieChart>
        <Pie
          activeIndex={activeIndex}
          activeShape={renderActiveShape}
          data={marketData}
          cx="50%" cy="50%"
          innerRadius={65} outerRadius={105}
          dataKey="value"
          onMouseEnter={onPieEnter}
        >
          {marketData.map((_, i) => (
            <Cell key={`cell-${i}`} fill={COLORS[i % COLORS.length]} stroke="none" />
          )}
        </Pie>
      </PieChart>
    </ResponsiveContainer>
  );
}

5. Custom Tooltips und Legends — Vollständig gestylt

Standard-Tooltips reichen für Prototypen — Production-Dashboards brauchen vollständig angepasste Tooltips mit korrekter Formatierung, Branding und kontextuellen Informationen. Recharts macht Custom Tooltips durch eine einfache Render-Prop möglich.

CustomTooltip.tsx — Vollständig gestylt tsx
interface TooltipProps {
  active?: boolean;
  payload?: Array<{ name: string; value: number; color: string; payload: DataPoint }>;
  label?: string;
}

function CustomTooltip({ active, payload, label }: TooltipProps) {
  if (!active || !payload?.length) return null;

  const revenue = payload.find(p => p.name === 'Umsatz')?.value ?? 0;
  const target = payload.find(p => p.name === 'Ziel')?.value ?? 0;
  const diff = revenue - target;
  const isAbove = diff >= 0;

  return (
    <div style={{
      background: '#1e293b',
      border: '1px solid #334155',
      borderRadius: '10px',
      padding: '12px 16px',
      minWidth: '180px',
      boxShadow: '0 8px 32px rgba(0,0,0,0.4)',
    }}>
      <p style={{ color: '#f1f5f9', fontWeight: 700, marginBottom: 8 }}>{label}</p>
      {payload.map((entry, i) => (
        <div key={i} style={{ display: 'flex', justifyContent: 'space-between', gap: 16, marginBottom: 4 }}>
          <span style={{ color: entry.color, fontSize: 13 }}>{entry.name}</span>
          <span style={{ color: '#e2e8f0', fontWeight: 600, fontSize: 13 }}>
            €{entry.value.toLocaleString('de-DE')}
          </span>
        </div>
      ))}
      <div style={{
        marginTop: 10, paddingTop: 8,
        borderTop: '1px solid #334155',
        display: 'flex', justifyContent: 'space-between'
      }}>
        <span style={{ color: '#64748b', fontSize: 12 }}>vs. Ziel</span>
        <span style={{ color: isAbove ? '#4ade80' : '#f87171', fontWeight: 700, fontSize: 12 }}>
          {isAbove ? '+' : ''}€{diff.toLocaleString('de-DE')}
        </span>
      </div>
    </div>
  );
}

// Verwendung im Chart:
<Tooltip content={<CustomTooltip />} cursor={{ fill: 'rgba(99,102,241,0.08)' }} />

Custom Legend — mit Klick-Toggle

ToggleLegend.tsx tsx
function CustomLegend({ payload, hiddenKeys, onToggle }: {
  payload?: Array<{ value: string; color: string }>;
  hiddenKeys: Set<string>;
  onToggle: (key: string) => void;
}) {
  return (
    <div style={{ display: 'flex', gap: 16, justifyContent: 'center', flexWrap: 'wrap', marginTop: 12 }}>
      {payload?.map(entry => {
        const hidden = hiddenKeys.has(entry.value);
        return (
          <button key={entry.value} onClick={() => onToggle(entry.value)}
            style={{
              display: 'flex', alignItems: 'center', gap: 6,
              background: 'none', border: 'none', cursor: 'pointer',
              opacity: hidden ? 0.35 : 1, transition: 'opacity 0.2s'
            }}>
            <span style={{ width: 12, height: 12, borderRadius: 3, background: entry.color }} />
            <span style={{ color: '#94a3b8', fontSize: 13 }}>{entry.value}</span>
          </button>
        );
      })}
    </div>
  );
}
Claude Code Pattern:

"Implementiere einen klickbaren Legend wo jede Serie ein- und ausgeblendet werden kann. Nutze useState für ein Set von versteckten dataKeys und filtere die entsprechenden Line/Bar-Komponenten." — Claude Code generiert das vollständige State-Management inklusive hide-Logik.

6. Performance: Memoization und große Datensätze

Recharts re-rendert bei jeder State-Änderung der Eltern-Komponente. In Dashboards mit häufigen Updates (Echtzeit-Daten, Filter-Interaktionen) wird das zum Bottleneck. Drei Strategien lösen das Problem:

Performance-Checkliste für Production-Dashboards

PerformanceChart.tsx — useMemo + React.memo tsx
import { useMemo, memo } from 'react';
import { LineChart, Line, ResponsiveContainer, XAxis, YAxis, Tooltip } from 'recharts';

// Data Thinning: Datensatz auf n Punkte reduzieren (Largest-Triangle-Three-Buckets)
function thinData<T>(data: T[], maxPoints: number): T[] {
  if (data.length <= maxPoints) return data;
  const step = Math.ceil(data.length / maxPoints);
  return data.filter((_, i) => i % step === 0);
}

interface Props {
  rawData: Array<{ ts: number; value: number }>;
  maxPoints?: number;
  isLive?: boolean;
}

// React.memo: Nur neu rendern wenn rawData, maxPoints oder isLive wechseln
export const PerformanceChart = memo(function PerformanceChart({ rawData, maxPoints = 200, isLive = false }: Props) {

  // useMemo: Thinning + Formatierung nur bei rawData-Änderung
  const chartData = useMemo(() => {
    const thinned = thinData(rawData, maxPoints);
    return thinned.map(d => ({
      ...d,
      time: new Date(d.ts).toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit' }),
    }));
  }, [rawData, maxPoints]);

  return (
    <ResponsiveContainer width="100%" height={240}>
      <LineChart data={chartData}>
        <XAxis dataKey="time" tick={{ fill: '#64748b', fontSize: 11 }} interval="preserveStartEnd" />
        <YAxis tick={{ fill: '#64748b', fontSize: 11 }} />
        <Tooltip />
        <Line
          type="monotone"
          dataKey="value"
          stroke="#6366f1"
          strokeWidth={1.5}
          dot={false} /* Dots deaktivieren bei vielen Punkten */
          isAnimationActive={!isLive} /* Keine Animation bei Live-Updates */
        />
      </LineChart>
    </ResponsiveContainer>
  );
});

Echtzeit-Daten mit useRef und requestAnimationFrame

LiveChart.tsx — Echtzeit ohne Render-Spam tsx
import { useState, useEffect, useRef, useCallback } from 'react';

const MAX_VISIBLE = 60; // Max 60 Punkte im Chart
const UPDATE_INTERVAL_MS = 1000; // Update-Rate: 1/Sekunde

export function LiveMetricChart({ dataStream }: { dataStream: EventSource }) {
  const [displayData, setDisplayData] = useState<DataPoint[]>([]);
  const bufferRef = useRef<DataPoint[]>([]);
  const lastFlushRef = useRef(0);

  // Buffer: Daten sammeln, nur jede Sekunde State updaten
  const flush = useCallback(() => {
    const now = Date.now();
    if (now - lastFlushRef.current < UPDATE_INTERVAL_MS) return;
    lastFlushRef.current = now;
    setDisplayData(prev => {
      const next = [...prev, ...bufferRef.current].slice(-MAX_VISIBLE);
      bufferRef.current = [];
      return next;
    });
  }, []);

  useEffect(() => {
    const handler = (e: MessageEvent) => {
      bufferRef.current.push(JSON.parse(e.data));
      flush();
    };
    dataStream.addEventListener('metric', handler);
    return () => dataStream.removeEventListener('metric', handler);
  }, [dataStream, flush]);

  return <PerformanceChart rawData={displayData} isLive={true} />;
}

Performance-Benchmarks (1.000 Datenpunkte, React 18)

Claude Code für Dashboard-Architektur

Claude Code denkt systemisch — nicht nur einzelne Chart-Komponenten, sondern vollständige Dashboard-Architekturen. Ein Prompt wie "Erstelle ein Sales-Dashboard mit Recharts: KPI-Cards oben, LineChart für Trend, BarChart für Kategorien, PieChart für Anteile — alle Daten aus einem useSalesData Hook, alle Charts memoized, Dark Theme" liefert eine vollständige, production-ready Implementierung.

Die KI kennt Recharts-Eigenheiten wie den ResponsiveContainer-Bug in Flex-Containern (Lösung: explizite Höhe oder width="99%"), den SVG-Clip-Path für benutzerdefinierte Shapes und das korrekte TypeScript-Typing aller Chart-Props. Was Entwickler sonst Stunden googeln, löst Claude Code in Sekunden.

Professionelle Dashboards mit Claude Code

Starte deinen kostenlosen Trial und lass Claude Code deine ersten Recharts-Dashboards generieren — von einfachen LineCharts bis zu komplexen ComposedCharts mit Custom Tooltips und Live-Updates.

Kostenlos Trial starten →
Recharts Claude Code Datenvisualisierung React LineChart BarChart PieChart Dashboard TypeScript Performance 2026