Patterns and gradients
Most charts tell their series apart by color alone. That leaves out people who see colors differently, and anyone looking at a printout in black and white. The WCAG success criterion 1.4.1 asks for a second way. Patterns are that second way: stripes, dots, or shapes drawn over the color of the series.
Wherever Recharts accepts a fill color for a shape that fills an area, it also accepts a fill object. A fill object has a solid color, and a definition that paints the shapes, such as a pattern or a gradient.
import { pattern, patterns } from 'recharts';
// A color, the same as always
<Bar dataKey="uv" fill="#8884d8" />
// A fill object: a solid color, and a definition that paints the shapes
<Bar dataKey="uv" fill={{ color: '#8884d8', definition: pattern(patterns.diagonal) }} />
// Without a color, the Bar keeps its theme color
<Bar dataKey="uv" fill={{ definition: pattern(patterns.diagonal) }} />Recharts renders the definition in SVG <defs> with a unique ID, and paints the shapes with it. You never write url(#…) or manage IDs yourself. Everything that needs a plain color uses the color: the Tooltip, the Legend text, and the labels. The Legend icon draws the same pattern.
If the fill object has no color, the shapes keep their color from the theme, and the pattern is drawn in that color. The texture of the built-in patterns is drawn in the pageBackground color of the theme, so it looks cut out of the shape in light and dark mode alike.
Built-in patterns
patterns holds the built-in patterns, and pattern turns one into a definition. The stripes and grids come first, then the same shapes as the Symbols in the Legend and in Scatter, two per tile in staggered rows. dots is the same pattern as circle.
A pattern is a plain object: the tile size, SVG path data, and how to draw it. Spread one of the built-in patterns to adjust it.
import { pattern, patterns } from 'recharts';
// Built-in patterns are plain objects, so you can adjust them by spreading
const denseDots = pattern({ ...patterns.dots, width: 6, height: 6 });
const darkStripes = pattern({ ...patterns.diagonal, color: '#000', opacity: 0.3 });Gradients
gradients holds the built-in linear gradients, and linearGradient turns one into a definition. They fade the base color of the fill, so they work with any color. The gradient stretches over each shape: over each bar, or here, over each area.
Custom patterns and definitions
There are two ways to draw your own fill. A custom pattern is a RechartsPattern object: a tile size, and SVG path data drawn in each tile. Recharts paints the base color under it. In small areas, such as a Legend icon, it draws the tiles smaller so that at least three fit.
For full control, write the definition yourself. A definition is a React component that renders an SVG paint server, such as a <linearGradient>, <radialGradient>, or <pattern>. It receives the id to put on its root element, the base color of the fill, and bounds: the size of the painted area, when it paints one area of known size. It renders inside the chart, so it can call hooks, Recharts hooks included.
Create definitions once, outside of your components. A new component on every render makes React remount the definition every time.
The Legend icon draws the definition with its own ID, and gives it the size of the icon as bounds. A definition sized in pixels, such as a <pattern> with patternUnits="userSpaceOnUse", can read bounds to fit the small icon. Recharts also passes bounds from a ReferenceArea, a ReferenceDot, and the Rectangle, Dot, Trapezoid, and Symbols shapes. It is undefined where one definition paints shapes of different sizes, such as every bar of a series. Gradients in the default units stretch over each shape anyway.
A fill for each data entry
Graphical items that draw one shape per data entry, like Bar, Pie, Funnel, RadialBar, Scatter, Treemap, SunburstChart, and the nodes of Sankey, read fill from each data entry too. A data entry can set a color, or a fill object. The data entry wins over the graphical item.
const data = [
{ name: 'Search', value: 400 },
// This sector paints with its own pattern
{ name: 'Direct', value: 300, fill: { definition: pattern(patterns.star) } },
// This sector has its own color, and no pattern
{ name: 'Social', value: 300, fill: '#ff7300' },
];
<Pie data={data} dataKey="value" fill={{ definition: pattern(patterns.diagonal) }} />Patterns in a theme
The fill of each theme entry in graphicalItems can be a fill object too, the same as the fill of a graphical item. Graphical items without a fill of their own then paint with it. Give each entry a different pattern, and every chart that uses the theme tells its series apart without relying on color alone, without setting a single fill.
Pie, Funnel, Treemap, SunburstChart, and Sankey take one theme entry per sector, trapezoid, branch, or node. The other graphical items take one per series. A graphical item or data entry that sets its own color does not take the theme pattern. A theme with fill objects holds React components, so it cannot be stored as JSON.
The other theme styles that fill an area take fill objects too: grid, reference, brush, barBackground, and cursor. A grid, reference element, Brush, background, or cursor without a fill of its own paints with the fill object of the theme. The active styles of a theme entry and the cross cursor of a ScatterChart use the color.
import { lightTheme, pattern, patterns } from 'recharts';
const theme = {
...lightTheme,
grid: { ...lightTheme.grid, fill: { color: '#fafafa', definition: pattern(patterns.dots) } },
reference: { ...lightTheme.reference, fill: { color: '#eee', definition: pattern(patterns.diagonal) } },
};Where fill objects work
| What | Where |
|---|---|
| Graphical items | The fill of Bar, Area, Radar, Scatter, Pie, RadialBar, Funnel, Treemap, and SunburstChart, and the fill of their data entries |
| Reference elements and grids | The fill of ReferenceArea, ReferenceDot, CartesianGrid, and PolarGrid, and each entry of horizontalFill and verticalFill |
| Active shapes and backgrounds | The object form of background, activeBar, activeShape, activeDot, dot, and the Tooltip cursor |
| Other components | The background of Brush, and the shapes: Rectangle, Sector, Trapezoid, Polygon, Symbols, Curve, and Dot |
const stripes = { color: '#eee', definition: pattern(patterns.diagonal) };
<CartesianGrid horizontalFill={['#fafafa', stripes]} />
<ReferenceArea x1="Feb" x2="Apr" fill={stripes} />
<Bar dataKey="uv" background={{ fill: stripes }} activeBar={{ fill: stripes }} />
<Tooltip cursor={{ fill: stripes }} />The shapes, active shapes, backgrounds, and the cursor have no theme color to fall back to, so give their fill objects a color. Labels and text keep plain colors, and so do the lines of a Line, the links of a Sankey, and the Brush travellers.