Command Palette

Search for a command to run...

Hectal
PHASE 14Advanced ~26 min· topic 4 of 7

Topic 14.4

Recharts in Depth

In one line

Recharts draws a chart from React components: a chart, its axes, a grid, a tooltip, a legend and one component per series. It is quick to start, and has a few traps: a container with no height, many points, gaps and the default accessibility.

Think of it like this

A flat-pack wardrobe. Every part (sides, shelves, doors) comes with holes in the right places. You choose the parts, put them in the frame, and it stands. You do not saw wood, but if you need a door of a different shape, you must read the manual.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

series
One set of marks for one field of the data: a Bar, a Line or an Area.
dataKey
The name of the field in each row that a component reads (dataKey="rides").
ResponsiveContainer
A Recharts component that measures its parent and gives the chart that width and height.
tick
One mark and label on an axis.
payload
What Recharts hands to a custom tooltip: the entries under the pointer, each with its value.
connectNulls
A Line option: draw a line across a missing value instead of leaving a gap.
accessibilityLayer
Recharts' built-in keyboard support and role="application" on the chart (on by default in version 3).

Step by step

01Parts in a frame

The first example is a bar chart of 12 monthly totals. BarChart takes the rows. Inside: a grid, two axes, a tooltip, a legend and one Bar. The shape function colours the busiest month orange and leaves the others teal.

a Recharts bar chartwhole filejsx
<ResponsiveContainer width="100%" height="100%">
  <BarChart data={data}>
    <XAxis dataKey="month" />
    <YAxis />
    <Tooltip />
    <Bar dataKey="rides" />
  </BarChart>
</ResponsiveContainer>

02Give the container a height

The second example mounts the same chart in three parents. A parent with a width and no height draws no bars and prints nothing. A parent with no width and no height prints a warning. A parent with both draws the chart.

03365 days, gaps and an empty state

The third example draws the whole year as a Line with three days missing. One chart leaves a gap, one joins across it and keeps the dots, and a third has no data at all.

04What you gain and lose

You get axes, tooltip, legend and keyboard support almost for free. You lose control over small details (tick placement rules, label collision), and you pay in size: the whole dashboard bundle with D3, React and Recharts was 614.64 kB (184.09 kB gzipped) when built for real on a small scratch dashboard (Topic 14.3), with Recharts and one D3 chart.

What you gain and losediagram
Rendering diagram…

Try it yourself

  1. 1

    Change which bar is highlighted

    In the first example change props.rides === top to props.month === "Dec". The shape function reads the row's fields, so orange bars: 1 still, but it is now December.

  2. 2

    Fix the trap with aspect

    In the second example give the first parent an aspect ratio instead of a height: change <ResponsiveContainer width="100%" height="100%"> to <ResponsiveContainer width="100%" aspect={2}>. With a width of 300, the container computes a height of 150, so the first parent now draws its 3 bars. The second parent (no width) still draws none and still warns, now with height(undefined) and aspect(2) in the message.

  3. 3

    Turn the dots off in the second chart

    In the third example change dots={true} to dots={false} for chart b. It prints line pieces: 1, dots: 0: the line is joined across the gap and the 362 circles are gone.

Code & diagrams

A bar chart of monthly rides with a custom tooltip and shape New tab

Hover a bar to see the custom tooltip, or press Tab and then the arrow keys. `isAnimationActive={false}` keeps this example still. The shape function receives the row's fields (`rides`) next to the geometry (`x`, `y`, `width`, `height`).

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

bars: 12 | y ticks: 5 | legend items: 1
orange bars: 1
chart svg: role = application | tabindex = 0 | title = Rides per month in 2025
The container trap: a parent with no height New tab

Only the third parent draws bars. Only the second one makes Recharts warn: the first fails silently, which is why this bug takes people a long time to find.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

width, no height    -> bars drawn: 0
The width(0) and height(0) of chart should be greater than 0,
       please check the style of container, or the props width(100%) and height(100%),
       or add a minWidth(0) or minHeight(undefined) or use aspect(undefined) to control the
       height and width.
no width, no height -> bars drawn: 0
width and height    -> bars drawn: 3
365 days: gaps, dots and an empty state New tab

Days 69 to 71 have no reading. In the first chart the line breaks there (2 pieces). In the second `connectNulls` draws across the gap, and the 362 dots (365 minus 3 missing days) are 362 extra SVG circles the first chart does not have.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

gap kept, dot={false}:   line pieces: 2, dots: 0
gap joined, with dots:   line pieces: 1, dots: 362
empty data:              No rides to show yet.

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

A parent with a width and no height

In the second example look at the first parent: <div style={{ width: 300 }}>.

terminal
$ Console
── what you'll see ──
width, no height -> bars drawn: 0
No error and no warning. The page shows an empty dashed box.

Break #2

A chart in a container that shrinks to its content

In the second example look at the second parent: display: "inline-block".

terminal
$ Console
── what you'll see ──
The width(0) and height(0) of chart should be greater than 0,
please check the style of container, or the props width(100%) and height(100%),
or add a minWidth(0) or minHeight(undefined) or use aspect(undefined) to control the
height and width.

Break #3

Pass data with a missing value to a bar chart, undecided

In the first example change February's total in totals, 44343, to null.

terminal
$ Console
── what you'll see ──
bars: 11 | y ticks: 5 | legend items: 1
orange bars: 1
chart svg: role = application | tabindex = 0 | title = Rides per month in 2025
Eleven bars are drawn: February's month label is still on the axis, but its bar is simply missing.

Myth vs fact

Myth

Recharts is slow because it is built on React.

Fact

It is as fast as any SVG chart: slow means too many SVG nodes. The default dots on a 365-point line, and animation on every update, are what usually hurt. Turn them off before changing library.

Myth

ResponsiveContainer always warns when it cannot draw.

Fact

It warns only when both sizes are 0. A parent with a width and no height is silent.

Myth

Recharts is accessible out of the box.

Fact

It adds keyboard focus and arrow-key tooltips, and a role="application". It does not name or describe the chart, and a keyboard user reads one point at a time. Add title and desc, and a data table.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    Recharts 3 rebuilt its internals around a Redux store and exposes hooks (for example useChartWidth, useActiveTooltipLabel) for custom components that need chart state. For anything beyond a Tooltip content function, read the hooks before copying private code.

  • ▸

    Cell still works but is deprecated and will be removed in 4.0. Prefer shape for per-mark styling in new code. Old blog posts and many answers still use Cell, so you will read it in codebases.

  • ▸

    ResponsiveContainer debounces nothing by default. For a heavy chart on a window drag, pass debounce={50} so the redraw waits until resizing pauses.

  • ▸

    A Line with type="monotone" smooths between points and can draw values that were never in the data (Topic 7.1). The default linear never lies; use monotone only when the smoothness is the point.

Remember this

  1. 1

    The problem this solves: writing every scale, axis, gridline and tooltip by hand (Topic 14.1) is correct and slow. Recharts gives you all of them as components, so a normal bar or line chart is about fifteen lines. It draws plain SVG, so everything you know about SVG still applies. This Phase uses Recharts 3.10.1.

  2. 2

    The parts. A chart component (BarChart, LineChart, AreaChart, ComposedChart) takes data, an array of objects. Inside it you place XAxis and YAxis (with dataKey naming the field), CartesianGrid, Tooltip, Legend, and one series component per field: Bar, Line, Area, each with dataKey. The order of children is the paint order.

  3. 3

    **ResponsiveContainer fills its parent.** Give it width="100%" and height="100%" and it measures the parent with a ResizeObserver. The parent therefore needs a real width and a real height from CSS. If the parent has no height, the chart has height 0 and draws nothing: the number one Recharts problem (second example).

  4. 4

    The size-0 warning is not reliable. Recharts logs a warning only when both the width and the height are 0. A parent that has a width but no height gives height 0 and no warning at all: the chart is silently empty. Always give the parent a height (height: 260), or pass aspect to the container.

  5. 5

    Customise with functions and elements. Tooltip takes content={<MyTip />}: Recharts passes active, payload and label. Bar takes shape={(props) => <Rectangle {...props} fill=... />} to colour or reshape single bars. The older Cell component still works but is deprecated and will be removed in Recharts 4.0. Tick text takes tick={{ fontSize: 12 }} or a component, and tickFormatter.

  6. 6

    Animation is on by default. A new bar grows and a changed line morphs, which is nice for a first draw and tiring when a chart updates every second. Set isAnimationActive={false} on the series, or respect prefers-reduced-motion (Topic 9.5) by setting it from matchMedia.

  7. 7

    Gaps, one point, empty data. A null value leaves a gap in a Line unless connectNulls is true. One point draws one dot only when dot is on (a single point has no line). An empty data array draws an empty frame with axes but no message: Recharts does not know what your empty state should say, so you write it (if (data.length === 0) return <p>...</p>), as in Topic 14.1.

  8. 8

    Many points. A default Line draws a dot for each point. For 365 days that is 365 extra SVG circles and a slow tooltip. Set dot={false}, keep activeDot for the hovered one, and turn animation off. Beyond a few thousand points, reduce the data (Topic 12.4) or draw to a canvas.

  9. 9

    Accessibility is on by default, and unfinished. Since Recharts 3 the chart's <svg> gets role="application" and tabIndex={0}, and the arrow keys move the tooltip (accessibilityLayer). It has no name or description until you set title and desc on the chart. Add them, and give people a table of the numbers (Topic 15.3).

Explain it without notes

01

Why does a Recharts chart sometimes draw nothing, with no error in the console, and what are two fixes?

02

How would you highlight one bar in Recharts 3 without the deprecated Cell?

03

A Line over 365 days is slow to hover. What do you change first?

04

What does Recharts do for accessibility by default, and what must you still add?

Practice

01

Write a StationsBar with Recharts for rows { name, rides }, horizontal (layout="vertical"), sorted busiest first, that shows a sentence for an empty list.

02

The chart in your app draws nothing. List, in order, the three things you check first.

Trade-offs

  • ↔

    Recharts is the quickest way to a standard, interactive, responsive chart and has the most users, but a custom visual (a calendar heatmap, an annotated timeline) fights its component model. D3 maths plus JSX scales to anything, at the cost of writing the parts yourself.

  • ↔

    Its default animation, dots and accessibility layer are tuned for demos. Production charts usually switch several of them off or replace them.

Done when you can

  • I can build a bar and a line chart with Recharts, with axes, tooltip and legend.

  • I can fix a chart that draws nothing because its container has no height.

  • I can style single bars with shape, knowing Cell is deprecated.

  • I can handle gaps, many points and empty data in a Recharts line chart.

  • I can add the name, description and data table that Recharts does not.