Skip to content
Charts

Recharts — Component Library Guide

Redefined chart library built with React and D3. Composable chart components - Line, Bar, Area, Pie, Radar, and more - built declaratively.

TypeScript MIT
3.2M weekly downloads
24.1k GitHub stars
~428kB bundle size
v2.15.1 latest version
chartsd3data-visualizationcomposablesvg

TL;DR: Recharts is a composable chart library for React built on D3. Combine <LineChart>, <Line>, <XAxis>, <Tooltip> as JSX. Wrap in <ResponsiveContainer> to scale with parent width. ~428kB uncompressed (~120kB gzipped). Official docs: recharts.org.

What is Recharts?

Recharts is a composable charting library that wraps D3 in React components. You build charts by composing primitives: <LineChart> + <Line> + <XAxis> + <Tooltip> + <Legend>. This declarative API makes it easy to add, remove, or customise chart elements without touching D3 internals.

When to use it

Use Recharts for standard business charts (line, bar, area, pie) in React apps when you don't need to write D3 directly.

Recharts vs Chart.js: Recharts is the natural choice for React apps - it's component-based and re-renders correctly. Chart.js uses canvas and requires manual cleanup. For complex or highly custom visualisations, consider Visx (D3 + React hooks, lower abstraction).

Note on bundle size: At ~428kB uncompressed (~120kB gzipped), Recharts is heavier than alternatives like Tremor or Victory. Consider lazy-loading chart components if they're not on the critical path.

How the composition model pays off

The reason Recharts feels natural to React developers is that a chart is just a tree of components. You don't call an imperative API and pass a giant config object. You write JSX, and each piece of the chart maps to a tag you can see. Want a grid? Add <CartesianGrid>. Need a second metric? Drop in another <Line> with a different dataKey. Remove a feature by deleting its element.

That model makes charts easy to read six months later, which is more valuable than it sounds. A config-object chart library tends to produce a wall of nested options where it's hard to tell what's actually rendered. With Recharts, a teammate can skim the JSX and know exactly what shows up on screen. It also means conditional rendering works the way you'd expect: wrap a <ReferenceLine> in a {showTarget && ...} and it appears or disappears with normal React logic.

The flip side is that deeply custom visualizations can fight the abstraction. If you need an unusual axis, a non-standard shape, or pixel-perfect control over every element, you'll spend time working around Recharts rather than with it. At that point a lower-level tool like Visx, which gives you D3 scales plus React rendering, is the better fit.

Making charts responsive and performant

ResponsiveContainer is the piece that makes charts adapt to their parent. It watches the parent's size and feeds the right width and height to the chart. The single most common Recharts bug is a chart that renders at zero height, and it's almost always because the parent has no defined height for the container to read. Give the parent an explicit height, or set a fixed height on the container itself, and the problem disappears.

Performance is mostly fine until two situations: large datasets and frequent updates. Recharts renders SVG, so every data point is a DOM node. A line with a few hundred points is fine; one with tens of thousands will get sluggish because the browser is managing that many nodes. For dense series, downsample your data before passing it in, or reach for a canvas-based library that doesn't pay the per-node cost.

The other one is animation on live data. Recharts animates transitions by default, which looks great on first load and terrible on a dashboard that refreshes every second, because each update restarts the animation and the chart visibly stutters. Set isAnimationActive={false} on your <Line>, <Bar>, or <Area> for any chart fed by polling or websockets. Keep the animation for static reports where it adds polish.

Customizing tooltips, axes, and annotations

Almost every real chart needs formatting the defaults don't provide. Axis ticks are the usual first stop. Use tickFormatter on <XAxis> or <YAxis> to turn raw numbers into currency, percentages, or compact notation, and to format timestamps into readable dates. This keeps the underlying data numeric, which matters because Recharts needs real numbers to compute scales correctly.

Tooltips are where you can add the most value with the least effort. The default tooltip is functional but plain. Passing your own component to <Tooltip content={...} /> gives you full JSX control, so you can show formatted values, add context, highlight the most important series, or match your brand styling exactly. Because it's a normal component, you can reuse the same number formatters you use elsewhere in the app.

For thresholds and targets, <ReferenceLine> and <ReferenceArea> let you annotate directly on the chart. A dashed reference line at a sales goal, or a shaded band marking an acceptable range, communicates far more than the raw series alone. These small additions are what separate a chart that merely plots data from one that tells the reader what to think about it.

Key Features

  • Composable - build any chart by combining axis, grid, tooltip, and data components
  • Responsive - <ResponsiveContainer> scales to parent dimensions
  • Custom tooltips - full JSX control over tooltip rendering
  • Reference lines/areas - annotate charts with threshold lines
  • Brush component - interactive timeline scrubber for zooming

Installation

npm install recharts

Basic Usage

import {
  LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer
} from 'recharts'

const data = [
  { month: 'Jan', users: 400, revenue: 2400 },
  { month: 'Feb', users: 620, revenue: 3800 },
  { month: 'Mar', users: 580, revenue: 3200 },
  { month: 'Apr', users: 890, revenue: 4800 },
]

function UsersChart() {
  return (
    <ResponsiveContainer width="100%" height={300}>
      <LineChart data={data}>
        <CartesianGrid strokeDasharray="3 3" stroke="#e2e8f0" />
        <XAxis dataKey="month" />
        <YAxis />
        <Tooltip />
        <Legend />
        <Line type="monotone" dataKey="users" stroke="#6366f1" strokeWidth={2} dot={false} />
        <Line type="monotone" dataKey="revenue" stroke="#10b981" strokeWidth={2} dot={false} />
      </LineChart>
    </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 className="bg-white border border-slate-200 rounded-lg p-3 shadow-lg text-sm">
      <p className="font-semibold text-slate-800 mb-1">{label}</p>
      {payload.map(entry => (
        <p key={entry.name} style={{ color: entry.color }}>
          {entry.name}: {entry.value.toLocaleString()}
        </p>
      ))}
    </div>
  )
}

// Usage:
<Tooltip content={<CustomTooltip />} />

TypeScript Tips

Type your data array to catch mismatched dataKey values early:

interface ChartDataPoint {
  month: string
  users: number
  revenue: number
}

const data: ChartDataPoint[] = [...]

// dataKey must match a key of ChartDataPoint
<Line dataKey="users" />       // matches a known key
<Line dataKey="sessions" />    // TypeScript won't catch this - Recharts uses string keys

Common Gotchas

  • ResponsiveContainer needs a defined parent height - if the parent has no height, the chart renders at 0px. Set height on ResponsiveContainer or ensure the parent has explicit height
  • Custom tick formatting - use tickFormatter on XAxis/YAxis for number/date formatting
  • Animation on data updates - Recharts animates by default. Set isAnimationActive={false} on chart elements for real-time data that updates frequently
  • TanStack Query - fetch and cache the data you pass to Recharts; handles loading, error, and refetch states
  • TanStack Table - pair a table with a chart for full data exploration: table for details, Recharts for overview

Frequently Asked Questions

Why is Recharts bundle size so large compared to other chart libraries?

Recharts bundles D3 internally, which accounts for most of the weight. The gzipped size is around 120kB. If bundle size is critical, consider Tremor Charts or lightweight alternatives built on Canvas. For most apps the trade-off is acceptable.

How do I make a Recharts chart responsive?

Wrap your chart component in ResponsiveContainer with width='100%' and set an explicit height. ResponsiveContainer listens to its parent's resize events and passes the correct dimensions to the chart.

Can I stop Recharts from animating on every data update?

Yes. Set isAnimationActive={false} on individual chart elements such as Line, Bar, or Area. For real-time or frequently updating data, disabling animation prevents visual jank.

How do I format axis tick values?

Use the tickFormatter prop on XAxis or YAxis. Pass a function that receives the raw value and returns a formatted string. For example, tickFormatter={(v) => v.toLocaleString()} for number formatting or a date-fns format call for dates.

What is the difference between Recharts and Victory?

Both are React-first chart libraries built on D3. Recharts uses a composable component API with separate Line, Bar, XAxis elements. Victory uses a similar composable approach but with slightly different naming conventions. Recharts has higher npm downloads and a larger community.