Recharts — Skill
Name: recharts
Purpose: Build responsive, readable charts with Recharts using correct data mapping and composition.
Use this skill whenever creating charts with Recharts.
Applies when: Using LineChart, BarChart, AreaChart, PieChart, ResponsiveContainer.
Do not use when: Charts are not built with Recharts.
Rules
- Always responsive: Wrap charts in
ResponsiveContainerand ensure a fixed height parent. - Explicit data model: Normalize data and use stable
dataKeyvalues. - Pick the simplest chart: Use
LineChartfor trends,BarChartfor comparisons,AreaChartfor cumulative/volume,PieChartfor part-to-whole. - Interactivity: Add
Tooltip; addLegendwhen multiple series exist. - Performance: Disable animation for large/static dashboards and reduce point count.
Workflow
- Define the data shape and stable keys.
- Choose the simplest chart that answers the question.
- Wrap in
ResponsiveContainerwith a height. - Add axes, tooltip, and legend as needed.
- Disable animation or aggregate data for large sets.
Checklists
Implementation checklist
- Chart is wrapped in
ResponsiveContainer - X/Y axes are present when needed
- Tooltip shows correct units
-
dataKeymatches field names
Review checklist
- Animations disabled for large datasets
- Colors are accessible
Minimal examples
Line chart (trend)
import {
LineChart,
Line,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
Legend,
ResponsiveContainer,
} from "recharts";
export function SalesChart({
data,
}: {
data: Array<{ month: string; sales: number }>;
}) {
return (
<div style={{ height: 320 }}>
<ResponsiveContainer width="100%" height="100%">
<LineChart
data={data}
margin={{ top: 8, right: 16, bottom: 8, left: 8 }}
>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="month" />
<YAxis />
<Tooltip />
<Legend />
<Line type="monotone" dataKey="sales" dot={false} />
</LineChart>
</ResponsiveContainer>
</div>
);
}
Custom tooltip
type TooltipProps = {
active?: boolean;
label?: string;
payload?: Array<{ name?: string; value?: number | string }>;
};
export function CustomTooltip({ active, label, payload }: TooltipProps) {
if (!active || !payload?.length) return null;
return (
<div className="rounded-md border bg-white p-2 text-sm shadow">
<div className="font-medium">{label}</div>
<ul className="mt-1 space-y-0.5">
{payload.map((p, i) => (
<li key={i}>
{p.name}: {p.value}
</li>
))}
</ul>
</div>
);
}
Common mistakes / pitfalls
- Missing
ResponsiveContaineror fixed-height parent - Mismatched
dataKeyvalues - Over-animating large dashboards
- Rendering too many points without aggregation