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, aLineor anArea. - 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
Lineoption: 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.
<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.
Try it yourself
- 1
Change which bar is highlighted
In the first example change
props.rides === toptoprops.month === "Dec". Theshapefunction reads the row's fields, soorange bars: 1still, but it is now December. - 2
Fix the trap with
aspectIn 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 withheight(undefined)andaspect(2)in the message. - 3
Turn the dots off in the second chart
In the third example change
dots={true}todots={false}for chart b. It printsline pieces: 1, dots: 0: the line is joined across the gap and the 362 circles are gone.
Code & diagrams
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
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 2025Only 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
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: 3Days 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
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 }}>.
Break #2
A chart in a container that shrinks to its content
In the second example look at the second parent: display: "inline-block".
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.
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 aTooltipcontent function, read the hooks before copying private code. - ▸
Cellstill works but is deprecated and will be removed in 4.0. Prefershapefor per-mark styling in new code. Old blog posts and many answers still useCell, so you will read it in codebases. - ▸
ResponsiveContainerdebounces nothing by default. For a heavy chart on a window drag, passdebounce={50}so the redraw waits until resizing pauses. - ▸
A
Linewithtype="monotone"smooths between points and can draw values that were never in the data (Topic 7.1). The defaultlinearnever lies; usemonotoneonly when the smoothness is the point.
Remember this
- 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
The parts. A chart component (
BarChart,LineChart,AreaChart,ComposedChart) takesdata, an array of objects. Inside it you placeXAxisandYAxis(withdataKeynaming the field),CartesianGrid,Tooltip,Legend, and one series component per field:Bar,Line,Area, each withdataKey. The order of children is the paint order. - 3
**
ResponsiveContainerfills its parent.** Give itwidth="100%"andheight="100%"and it measures the parent with aResizeObserver. 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
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 passaspectto the container. - 5
Customise with functions and elements.
Tooltiptakescontent={<MyTip />}: Recharts passesactive,payloadandlabel.Bartakesshape={(props) => <Rectangle {...props} fill=... />}to colour or reshape single bars. The olderCellcomponent still works but is deprecated and will be removed in Recharts 4.0. Tick text takestick={{ fontSize: 12 }}or a component, andtickFormatter. - 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 respectprefers-reduced-motion(Topic 9.5) by setting it frommatchMedia. - 7
Gaps, one point, empty data. A
nullvalue leaves a gap in aLineunlessconnectNullsis true. One point draws one dot only whendotis on (a single point has no line). An emptydataarray 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
Many points. A default
Linedraws a dot for each point. For 365 days that is 365 extra SVG circles and a slow tooltip. Setdot={false}, keepactiveDotfor the hovered one, and turn animation off. Beyond a few thousand points, reduce the data (Topic 12.4) or draw to a canvas. - 9
Accessibility is on by default, and unfinished. Since Recharts 3 the chart's
<svg>getsrole="application"andtabIndex={0}, and the arrow keys move the tooltip (accessibilityLayer). It has no name or description until you settitleanddescon the chart. Add them, and give people a table of the numbers (Topic 15.3).
Explain it without notes
Why does a Recharts chart sometimes draw nothing, with no error in the console, and what are two fixes?
How would you highlight one bar in Recharts 3 without the deprecated Cell?
A Line over 365 days is slow to hover. What do you change first?
What does Recharts do for accessibility by default, and what must you still add?
Practice
Write a StationsBar with Recharts for rows { name, rides }, horizontal (layout="vertical"), sorted busiest first, that shows a sentence for an empty list.
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, knowingCellis 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.