Exploring Recharts: what can be rendered inside a Recharts container?

Gaurav Gupta
5 min readJun 21, 2020

--

The top level charts in Recharts act as a container for other elements which can be rendered inside it. Some examples are LineChart, BarChart. These charts act as top level containers for other elements like Line, Bar, Tooltip, ReferenceLine, ReferenceDot, XAxis, etc.
Unlike many other charting libraries which allow all of this configuration and customizations by passing props or parameters to the top level container (which then takes care of rendering everything), Recharts allows you to have full control on what should be rendered inside the container and allows each of the children to be customized separately, while also making sure that each of these children get the required context from the parent.

As an example, consider this example taken from another good charting library Nivo:

and now consider a similar example in Recharts:

It is a lot easier on the eyes and it allows to customize each child element separately, so you can pass props to Tooltip, XAxis, YAxis, etc, as you would pass to any React components. Also note that the Linechart would implicitly pass on the required data to Tooltip, i.e, what is the y-value and x-value of the point being hovered over, while also allowing the developer to customize other things in Tooltip through explicit props. .

This very much aligns with how React components are composed. Of course, even when allowing this kind of flexibility, Recharts still has to make sure that only appropriate elements are rendered within appropriate parents, for example, you shouldn’t expect to be able to render a Line inside a PieChart, and correctly so, Recharts explicitly disallows this.

How does rechart disallow certain elements?

Recharts checks the type of the element being rendered, and if does not match the allowed types, it would just simply ignore that element. It does not show an error or warning and excludes that element from the rendered output.

Recharts does not render html element inside the main container

In the above codesandbox, Recharts does not render the div element at all.

In some ways this is good, because accidentally rendering a wrong component does not break the UI, but it is also not the best developer experience as you do not get any warnings on the console even in developer mode, when you try to render an inappropriate component.

So, what can you render inside a top level container ?

  • Recharts provided components
  • svg elements
  • foreignobject
  • DOM elements
  • Custom Components (?)

Recharts provided components:

As seen in our example above and as mentioned in the Recharts documentation, every top level container (or rather, every Recharts component) can only render certain Recharts provided components. For example, LineChart can render Line, Tooltip, ReferenceArea, xAxis, yAxis, and so on, but not a Bar.

SVG elements:

The top level chart containers render an svg element internally and allow any elements to be rendered inside the svg as per the svg spec. So, you can render circle, rect, g, and a lot of other svg elements directly inside the top level container. This allows for some level of customization, but there are some drawbacks. Recharts doesn’t/can’t pass any context to these svg elements, so let’s say you want to render a circle inside the chart at a particular x-value from your data, then you would have to explicitly do the scale calculations and figure out the cx and cy of this circle in cartesian coordinates (this is difficult as Recharts does not directly expose the xAxis and yAxis scales, so that you can map the data coordinates to cartesian coordinates), instead you can just use the ReferenceDot component provided by Recharts, pass on the x-value from the data and Recharts would take care of rendering the circle in the appropriate transformed coordinates in the cartesian coordinate system.

Also, not all Recharts components allow all the appropriate svg elements, for example, although a ReferenceDot renders a circle, and in svg, a circle can have an animate element, if you try to pass animate as a child to ReferenceDot, it would be ignored.

But you can at least rely on this functionality at the top level container.

foreignObject

This capability is not specifically provided by Recharts, rather, the svg specs allow this. As we discussed above, Recharts allows rendering Recharts provided components inside the top level container, we also saw that the top level container is an svg and so we can render svg elements directly inside it, like circle, rect, etc. But, manipulating svg elements is sometimes much more difficult than manipulating regular DOM elements, for e.g, centering text in svg using the text element is much more difficult than centering text in a div. So, for such usages, svg specs allow rendering HTML elements inside svg using a foreignObject.

foreignObject is helpful when customizing Recharts provided elements.

DOM elements

Unfortunately, Recharts would simply ignore any DOM elements that we try to directly render inside the chart container, but as we have seen above, we can enable this using a foreignObject. Also, as a side note, although most of the Recharts components only allow svg elements to be used in customization , like when customizing label, or using the shape prop, Tooltip is one component that allows customization using HTML . This is possible because the Tooltip is actually rendered by Recharts outside the svg and so it does not have the same limitations as the other Recharts components.

Custom components:

So what about custom components ?

Can we create a new React component which returns an svg element and render it inside the top level chart container ? No.

Can we create a new React component which returns a foreignObject element and render it inside the top level chart container ? No.

Can we create a new react component which returns a Recharts component and render it inside the top level chart container ? Sadly, No.

As discussed above, Recharts explicitly checks for the type of element/component being rendered and ignores if the type does not match any allowed types, so although your React component returns the appropriate Recharts component, the type of the React component (or the class/constructor function, for simplicity), is something that Recharts does not have in its “allow” list and hence it ignores it completely.

So, if you can’t provide Custom components, how do you customize things in Recharts? Well, for all the components that allow customization, Recharts exposes this capability through props.

For components which support labels, you can pass in a function which renders a custom label.

For Tooltip, you can pass in a function/React component in the content prop which renders a custom Tooltip.

For ReferenceDot, you can pass in a function in the shape prop. This function can return any svg element which should be rendered as the ReferenceDot.

For all these examples, Recharts passes on the required context to this function/React component and you can use this information to render anything you want.

A list of all other posts in this series:

--

--