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?
- Recharts: React-Apps, Dashboards, Business Intelligence, TypeScript-Projekte
- Chart.js: Wenn Canvas-Rendering nötig ist (sehr viele Datenpunkte >10.000)
- D3.js: Hochkomplexe, einmalige Visualisierungen mit vollständiger Kontrolle
Installation und Claude Code Setup
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
Einsatzgebiete
- Zeitreihen (Umsatz, Traffic, Metriken über Zeit)
- Mehrere Datenserien vergleichen (A/B-Tests, Produkte)
- Trends und Anomalien visualisieren
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.
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>
);
}
"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
Drei Modi
- Gruppiert: Mehrere Balken nebeneinander pro Kategorie
- Gestapelt (stacked): Anteile innerhalb einer Kategorie
- ComposedChart: Balken + Linie kombiniert (z.B. Umsatz + Wachstumsrate)
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
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
Anwendungsfälle
- Marktanteile, Budgetverteilung, Kategorie-Aufschlüsselung
- Active Shape für interaktive Segments
- Custom Labels außerhalb oder innerhalb der Sektoren
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.
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
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>
);
}
"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
- useMemo für Datentransformation — Berechnung nur bei Datenwechsel
- React.memo für Chart-Komponenten — Kein Re-Render bei unbeteiligten Props
- Data Thinning — Große Datensätze auf sinnvolle Punkte reduzieren
- isAnimationActive={false} — Deaktiviert bei Echtzeit-Updates (>1/Sek)
- Virtual Rendering — Nur sichtbarer Zeitraum laden (Windowing)
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
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)
- Ohne Optimierung: ~180ms Re-Render bei jedem State-Update
- Mit React.memo: ~45ms (unbeteiligte Updates ignoriert)
- Mit useMemo + Thinning: ~12ms (Datentransformation gecacht)
- Mit Buffer + 1s Flush: Nur 1 Render/Sekunde statt >10
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 →