Recharts is a composable charting library built on React components and powered by D3.js under the hood. Unlike lower-level D3 bindings that require manual DOM manipulation, Recharts exposes every chart element—axes, tooltips, legends, gridlines, data series—as a declarative React component. This means chart construction follows the same mental model as building any other React UI: compose components, pass props, and let the framework handle rendering and updates.
The library covers the most common chart types used in data dashboards and analytics UIs: line charts, area charts, bar charts, pie charts, scatter plots, radar charts, and tree maps. Each chart type is built from shared primitives like XAxis, YAxis, Tooltip, Legend, and ResponsiveContainer, which makes switching between chart types or composing hybrid visualizations straightforward.
Recharts is particularly well-suited for React applications that need interactive data displays with dark mode support, responsive sizing, and customizable tooltips. It handles the complex SVG coordinate math internally while exposing enough customization hooks (custom tick formatters, shape renderers, event handlers) to cover most production charting needs without dropping down to raw D3.
Every visual element in a Recharts chart is a React component. An AreaChart contains Area, XAxis, YAxis, Tooltip, and CartesianGrid as children. This compositional model means you add features by adding components rather than configuring a monolithic options object. Removing a tooltip is as simple as removing the <Tooltip /> child.
Charts in Recharts have fixed dimensions by default. The ResponsiveContainer wrapper component makes charts resize fluidly with their parent container. It uses a ResizeObserver internally to detect size changes and re-renders the chart at the new dimensions. This is essential for dashboard layouts where chart panels resize based on viewport or grid column changes.
Recharts expects data as an array of plain objects where each object represents one data point. The keys in each object map to dataKey props on series components. For example, [{ date: "Jan", revenue: 4000, cost: 2400 }] would feed an Area with dataKey="revenue" and another with dataKey="cost". This flat structure keeps the data layer simple and decoupled from the chart configuration.
Recharts supports custom tooltip rendering via a content prop that accepts a React component. The custom component receives the active payload, label, and coordinate data, enabling fully styled tooltip UIs that match your application’s design system. Similarly, axis tick formatters, label components, and legend renderers are all customizable through render props or component overrides.
Recharts animates chart transitions by default using CSS transitions on SVG elements. When data updates, series components interpolate between old and new values with configurable duration, easing, and delay. Animations can be disabled globally or per-component for performance-sensitive scenarios like real-time data streams where smooth transitions would lag behind incoming data.
The simplest Recharts chart requires a chart container component, at least one data series component, and a data array. The chart container (AreaChart, LineChart, BarChart, etc.) receives the data and dimensions, while child components reference specific data keys.
import {
AreaChart, Area, XAxis, YAxis, CartesianGrid,
Tooltip, ResponsiveContainer, Legend,
} from 'recharts';
const data = [
{ month: 'Jan', queries: 4000, latency: 24 },
{ month: 'Feb', queries: 3800, latency: 22 },
{ month: 'Mar', queries: 5200, latency: 28 },
{ month: 'Apr', queries: 4900, latency: 26 },
{ month: 'May', queries: 6100, latency: 31 },
{ month: 'Jun', queries: 5800, latency: 29 },
];
const QueryChart = () => (
<ResponsiveContainer width="100%" height={400}>
<AreaChart data={data} margin={{ top: 10, right: 30, left: 0, bottom: 0 }}>
<defs>
<linearGradient id="colorQueries" x1="0" y1="0" x2="0" y2="1">
<stop offset="5%" stopColor="#6c63ff" stopOpacity={0.3} />
<stop offset="95%" stopColor="#6c63ff" stopOpacity={0} />
</linearGradient>
</defs>
<CartesianGrid strokeDasharray="3 3" stroke="#2a2d40" />
<XAxis dataKey="month" stroke="#6b6785" fontSize={12} />
<YAxis stroke="#6b6785" fontSize={12} />
<Tooltip />
<Legend />
<Area
type="monotone"
dataKey="queries"
stroke="#6c63ff"
fillOpacity={1}
fill="url(#colorQueries)"
/>
</AreaChart>
</ResponsiveContainer>
);
Recharts renders charts as SVG, which means standard SVG features like linear gradients, radial gradients, and patterns are available. The <defs> block inside the chart defines reusable gradient elements that series components reference via fill="url(#gradientId)". This technique produces the smooth color-fade effect commonly seen in modern dashboard area charts.
The XAxis and YAxis components accept tickFormatter functions for display formatting, tick render props for fully custom tick elements, and domain arrays to control the scale range. For time-series data, the scale="time" prop combined with type="number" enables D3’s time scale for proper date axis spacing.
An internal component library uses Recharts for its analytics dashboard components, rendering query volume, response time distributions, and error rate trends. Area charts with gradient fills provide visual density information at a glance, while tooltips show exact values on hover. The charts are wrapped in ResponsiveContainer to adapt to the dashboard grid layout, and dark mode theming is applied through custom axis colors and tooltip styling that matches the application’s design tokens.
For monitoring views in internal tooling, Recharts renders time-series metrics like CPU utilization, memory pressure, and request throughput. Multiple Area components are stacked using stackId to show aggregate resource consumption broken down by service. Real-time updates push new data points into the array while trimming old ones, creating a sliding window effect without chart re-initialization.
Bar charts with grouped bars enable side-by-side comparisons of metrics across categories or time periods. Custom bar shapes and labels highlight outliers or threshold violations. The ReferenceLine component overlays target values or SLA thresholds directly on the chart, providing immediate visual context for whether metrics are within acceptable ranges.
This pattern shows a fully custom tooltip component that matches a dark-themed dashboard design, with formatted values and a styled container.
import { TooltipProps } from 'recharts';
interface CustomTooltipProps extends TooltipProps<number, string> {}
const DarkTooltip: React.FC<CustomTooltipProps> = ({ active, payload, label }) => {
if (!active || !payload?.length) return null;
return (
<div style={{
background: '#1c1f2e',
border: '1px solid #2a2d40',
borderRadius: 8,
padding: '12px 16px',
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.3)',
}}>
<p style={{ color: '#e8e6f0', fontSize: 13, fontWeight: 600, marginBottom: 8 }}>
{label}
</p>
{payload.map((entry, index) => (
<div key={index} style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 4 }}>
<span style={{
width: 8, height: 8, borderRadius: '50%',
background: entry.color, display: 'inline-block',
}} />
<span style={{ color: '#9995b0', fontSize: 12 }}>{entry.name}:</span>
<span style={{ color: '#e8e6f0', fontSize: 12, fontWeight: 600 }}>
{typeof entry.value === 'number' ? entry.value.toLocaleString() : entry.value}
</span>
</div>
))}
</div>
);
};
// Usage
<Tooltip content={<DarkTooltip />} cursor={{ stroke: '#6c63ff', strokeWidth: 1 }} />
This pattern demonstrates managing series visibility through legend interaction, allowing users to focus on specific metrics by clicking legend entries.
import { useState, useCallback } from 'react';
import {
AreaChart, Area, XAxis, YAxis, CartesianGrid,
Tooltip, ResponsiveContainer, Legend,
} from 'recharts';
interface MetricData {
timestamp: string;
reads: number;
writes: number;
deletes: number;
}
const SERIES = [
{ key: 'reads', color: '#6c63ff', label: 'Read Ops' },
{ key: 'writes', color: '#00d4aa', label: 'Write Ops' },
{ key: 'deletes', color: '#ff6b8a', label: 'Delete Ops' },
] as const;
const MetricsChart: React.FC<{ data: MetricData[] }> = ({ data }) => {
const [hidden, setHidden] = useState<Set<string>>(new Set());
const handleLegendClick = useCallback((entry: { dataKey?: string }) => {
if (!entry.dataKey) return;
setHidden((prev) => {
const next = new Set(prev);
if (next.has(entry.dataKey!)) {
next.delete(entry.dataKey!);
} else {
next.add(entry.dataKey!);
}
return next;
});
}, []);
return (
<ResponsiveContainer width="100%" height={350}>
<AreaChart data={data}>
<CartesianGrid strokeDasharray="3 3" stroke="#2a2d40" />
<XAxis dataKey="timestamp" stroke="#6b6785" fontSize={11} />
<YAxis stroke="#6b6785" fontSize={11} />
<Tooltip content={<DarkTooltip />} />
<Legend onClick={handleLegendClick} wrapperStyle={{ cursor: 'pointer' }} />
{SERIES.map(({ key, color, label }) => (
<Area
key={key}
type="monotone"
dataKey={key}
name={label}
stroke={color}
fill={color}
fillOpacity={hidden.has(key) ? 0 : 0.15}
strokeOpacity={hidden.has(key) ? 0.2 : 1}
strokeWidth={hidden.has(key) ? 1 : 2}
/>
))}
</AreaChart>
</ResponsiveContainer>
);
};
This pattern uses reference lines to overlay SLA thresholds on a bar chart, providing immediate visual context for whether metrics meet targets.
import {
BarChart, Bar, XAxis, YAxis, CartesianGrid,
Tooltip, ResponsiveContainer, ReferenceLine, Cell,
} from 'recharts';
interface LatencyData {
endpoint: string;
p50: number;
p99: number;
}
const SLA_THRESHOLD = 200; // ms
const LatencyChart: React.FC<{ data: LatencyData[] }> = ({ data }) => (
<ResponsiveContainer width="100%" height={300}>
<BarChart data={data} layout="vertical" margin={{ left: 120 }}>
<CartesianGrid strokeDasharray="3 3" stroke="#2a2d40" horizontal={false} />
<XAxis type="number" stroke="#6b6785" fontSize={11} unit="ms" />
<YAxis
type="category"
dataKey="endpoint"
stroke="#6b6785"
fontSize={11}
width={110}
/>
<Tooltip content={<DarkTooltip />} />
<ReferenceLine
x={SLA_THRESHOLD}
stroke="#ff6b8a"
strokeDasharray="4 4"
label={{ value: 'SLA', fill: '#ff6b8a', fontSize: 11 }}
/>
<Bar dataKey="p99" name="P99 Latency" radius={[0, 4, 4, 0]}>
{data.map((entry, index) => (
<Cell
key={index}
fill={entry.p99 > SLA_THRESHOLD ? '#ff6b8a' : '#00d4aa'}
/>
))}
</Bar>
</BarChart>
</ResponsiveContainer>
);
ResponsiveContainer, charts render at their hardcoded width and height props (defaulting to 0 if omitted). This is the most common cause of “invisible charts.” Always wrap charts in ResponsiveContainer with explicit width/height or percentage values, and ensure the parent element has a defined height.dataKey prop must exactly match a key in the data objects. A typo or casing difference results in a chart that renders axes but no data series, with no error or warning. Use TypeScript interfaces for data shapes and verify data keys match at compile time.id attributes must be unique across the entire document. Reusing the same gradient ID causes charts to reference each other’s gradients, producing unexpected colors. Namespace gradient IDs with the chart’s purpose or use dynamically generated IDs.isAnimationActive={false}, and consider virtualized approaches for truly massive datasets.position prop to lock tooltip placement.ResponsiveContainer. During server-side rendering, dimensions are unavailable, causing layout shifts on hydration. Use width and height props as initial values and lazy-load ResponsiveContainer on the client.