React Charts with Recharts: Bar, Line and Pie Charts (2026)
Recharts is the most widely-used charting library for React — built on D3 under the hood, but with a declarative React API. It handles responsiveness, animations, tooltips and legends out of the box. This guide covers every major chart type with dark-theme styling and production-ready patterns.
Table of Contents
Setup and ResponsiveContainer
npm install recharts
import { ResponsiveContainer, BarChart, Bar } from 'recharts'
// Always wrap in ResponsiveContainer for fluid width
function MyChart() {
return (
<ResponsiveContainer width="100%" height={300}>
<BarChart data={data}>
<Bar dataKey="value" />
</BarChart>
</ResponsiveContainer>
)
}
BarChart
import {
BarChart, Bar, XAxis, YAxis, CartesianGrid,
Tooltip, Legend, ResponsiveContainer, Cell
} from 'recharts'
const revenueData = [
{ month: 'Jan', revenue: 42000, expenses: 28000 },
{ month: 'Feb', revenue: 53000, expenses: 31000 },
{ month: 'Mar', revenue: 48000, expenses: 29000 },
{ month: 'Apr', revenue: 61000, expenses: 35000 },
{ month: 'May', revenue: 55000, expenses: 32000 },
{ month: 'Jun', revenue: 67000, expenses: 38000 },
]
function RevenueChart() {
return (
<ResponsiveContainer width="100%" height={300}>
<BarChart data={revenueData} margin={{ top: 5, right: 30, left: 20, bottom: 5 }}>
<CartesianGrid strokeDasharray="3 3" stroke="rgba(99,102,241,0.15)" />
<XAxis dataKey="month" stroke="#64748b" tick={{ fill: '#94a3b8' }} />
<YAxis stroke="#64748b" tick={{ fill: '#94a3b8' }} tickFormatter={v => `$${v/1000}k`} />
<Tooltip content={<CustomTooltip />} />
<Legend />
<Bar dataKey="revenue" fill="#6366f1" radius={[4, 4, 0, 0]} name="Revenue" />
<Bar dataKey="expenses" fill="#22d3ee" radius={[4, 4, 0, 0]} name="Expenses" />
</BarChart>
</ResponsiveContainer>
)
}
// Stacked bar chart
<BarChart data={data}>
<Bar dataKey="desktop" stackId="a" fill="#6366f1" />
<Bar dataKey="mobile" stackId="a" fill="#22d3ee" radius={[4, 4, 0, 0]} />
</BarChart>
// Bar with individual cell colors
<Bar dataKey="value">
{data.map((entry, index) => (
<Cell key={index} fill={entry.value > 0 ? '#22c55e' : '#ef4444'} />
))}
</Bar>
LineChart and AreaChart
import { LineChart, Line, AreaChart, Area } from 'recharts'
const trafficData = [
{ date: 'Mon', pageviews: 1200, sessions: 800 },
{ date: 'Tue', pageviews: 1900, sessions: 1100 },
{ date: 'Wed', pageviews: 1600, sessions: 950 },
{ date: 'Thu', pageviews: 2100, sessions: 1400 },
{ date: 'Fri', pageviews: 1800, sessions: 1200 },
{ date: 'Sat', pageviews: 900, sessions: 600 },
{ date: 'Sun', pageviews: 750, sessions: 500 },
]
function TrafficLineChart() {
return (
<ResponsiveContainer width="100%" height={300}>
<LineChart data={trafficData}>
<CartesianGrid strokeDasharray="3 3" stroke="rgba(99,102,241,0.15)" />
<XAxis dataKey="date" stroke="#64748b" tick={{ fill: '#94a3b8' }} />
<YAxis stroke="#64748b" tick={{ fill: '#94a3b8' }} />
<Tooltip content={<CustomTooltip />} />
<Legend />
<Line
type="monotone"
dataKey="pageviews"
stroke="#6366f1"
strokeWidth={2}
dot={{ r: 4, fill: '#6366f1' }}
activeDot={{ r: 6 }}
name="Page Views"
/>
<Line
type="monotone"
dataKey="sessions"
stroke="#22d3ee"
strokeWidth={2}
dot={false}
name="Sessions"
/>
</LineChart>
</ResponsiveContainer>
)
}
// Gradient area chart
function GradientAreaChart() {
return (
<ResponsiveContainer width="100%" height={300}>
<AreaChart data={trafficData}>
<defs>
<linearGradient id="colorPageviews" 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="rgba(99,102,241,0.15)" />
<XAxis dataKey="date" tick={{ fill: '#94a3b8' }} />
<YAxis tick={{ fill: '#94a3b8' }} />
<Tooltip />
<Area
type="monotone"
dataKey="pageviews"
stroke="#6366f1"
strokeWidth={2}
fill="url(#colorPageviews)"
/>
</AreaChart>
</ResponsiveContainer>
)
}
PieChart and DonutChart
import { PieChart, Pie, Cell, Tooltip, Legend } from 'recharts'
const browserData = [
{ name: 'Chrome', value: 65 },
{ name: 'Safari', value: 18 },
{ name: 'Firefox', value: 10 },
{ name: 'Edge', value: 7 },
]
const COLORS = ['#6366f1', '#22d3ee', '#f59e0b', '#10b981']
function BrowserPieChart() {
return (
<ResponsiveContainer width="100%" height={300}>
<PieChart>
<Pie
data={browserData}
cx="50%"
cy="50%"
outerRadius={100}
dataKey="value"
label={({ name, percent }) => `${name} ${(percent * 100).toFixed(0)}%`}
labelLine={true}
>
{browserData.map((_, index) => (
<Cell key={index} fill={COLORS[index % COLORS.length]} />
))}
</Pie>
<Tooltip formatter={(value) => [`${value}%`, 'Share']} />
</PieChart>
</ResponsiveContainer>
)
}
// Donut chart — add innerRadius
<Pie
data={browserData}
cx="50%"
cy="50%"
innerRadius={60} // Creates donut hole
outerRadius={100}
dataKey="value"
paddingAngle={3} // Gap between segments
>
ComposedChart
import { ComposedChart, Bar, Line, Area } from 'recharts'
// Mix chart types in one chart
function SalesComposedChart() {
return (
<ResponsiveContainer width="100%" height={300}>
<ComposedChart data={data}>
<CartesianGrid strokeDasharray="3 3" stroke="rgba(99,102,241,0.15)" />
<XAxis dataKey="month" tick={{ fill: '#94a3b8' }} />
<YAxis yAxisId="left" tick={{ fill: '#94a3b8' }} />
<YAxis yAxisId="right" orientation="right" tick={{ fill: '#94a3b8' }} />
<Tooltip />
<Legend />
<Bar yAxisId="left" dataKey="orders" fill="#6366f1" radius={[4,4,0,0]} />
<Line yAxisId="right" type="monotone" dataKey="revenue" stroke="#22d3ee" strokeWidth={2} />
<Area yAxisId="left" type="monotone" dataKey="target" fill="rgba(34,211,238,0.1)" stroke="#22d3ee" strokeDasharray="5 5" />
</ComposedChart>
</ResponsiveContainer>
)
}
Custom Tooltip
interface TooltipProps {
active?: boolean
payload?: Array<{ name: string; value: number; color: string }>
label?: string
}
function CustomTooltip({ active, payload, label }: TooltipProps) {
if (!active || !payload?.length) return null
return (
<div style={{
background: '#0d1424',
border: '1px solid rgba(99,102,241,0.3)',
borderRadius: 8,
padding: '12px 16px',
}}>
<p style={{ color: '#94a3b8', marginBottom: 8, fontSize: 12 }}>{label}</p>
{payload.map((entry) => (
<div key={entry.name} 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: '#e2e8f0', fontSize: 13 }}>
{entry.name}: <strong>{entry.value.toLocaleString()}</strong>
</span>
</div>
))}
</div>
)
}
Real-Time Data
function RealTimeChart() {
const [data, setData] = useState(() =>
Array.from({ length: 20 }, (_, i) => ({ time: i, value: Math.random() * 100 }))
)
useEffect(() => {
const interval = setInterval(() => {
setData(prev => [
...prev.slice(1), // Remove oldest point
{ time: prev[prev.length - 1].time + 1, value: Math.random() * 100 }
])
}, 1000)
return () => clearInterval(interval)
}, [])
return (
<ResponsiveContainer width="100%" height={200}>
<LineChart data={data}>
<Line
type="monotone"
dataKey="value"
stroke="#6366f1"
dot={false}
isAnimationActive={false} // Disable animation for real-time — prevents flicker
/>
<YAxis domain={[0, 100]} tick={{ fill: '#94a3b8' }} />
<Tooltip />
</LineChart>
</ResponsiveContainer>
)
}
Dark Theme Styling
// Global dark theme defaults — apply to all chart components
const darkTheme = {
cartesianGrid: { stroke: 'rgba(99,102,241,0.15)', strokeDasharray: '3 3' },
axis: { stroke: '#1e293b', tick: { fill: '#64748b', fontSize: 12 } },
tooltip: {
contentStyle: {
background: '#0d1424',
border: '1px solid rgba(99,102,241,0.3)',
borderRadius: 8,
color: '#e2e8f0',
},
labelStyle: { color: '#94a3b8' },
cursor: { fill: 'rgba(99,102,241,0.08)' },
},
legend: { wrapperStyle: { color: '#94a3b8', fontSize: 13 } },
}
// Usage
<Tooltip
contentStyle={darkTheme.tooltip.contentStyle}
labelStyle={darkTheme.tooltip.labelStyle}
cursor={darkTheme.tooltip.cursor}
/>