Skip to content
Folio

Charts

ComposedChart

Bars and lines over one axis — the volume, and the rate it moved at.

Usage

When to reach for it

Two measures that share a scale. Two that do NOT share one belong in two charts or indexed to a common base: there is no second y-axis here, on purpose.

Ships from@misoto22/design/charts

TSX
import { ComposedChart } from '@misoto22/design/charts'

Notes

Bars and lines over one axis — the shape for "the volume, and the rate it moved at".

One axis, always. Two measures at different scales belong in two charts or indexed to a common base; a second y-scale lets the author choose where the lines cross, which is the single most misleading thing a chart can do.

Anatomy

ComposedChart anatomy
ElementDescription
Figure framerequiredChartFigure’s <figure>, named by title, with the composed marks inside one measured ChartContainer.
The single value axisrequired<ComposedChart.YAxis>. One of them is the entire design: there is no dual-axis affordance and no second scale to configure, so the two measures are read against the same numbers.
Bars<ComposedChart.Bar>, the volume. Custom-shaped like BarChart’s, with the same transparent hit rectangle and the same grow-in anchored to the chart’s start rather than to each bar’s mount, so a hover cannot replay it.
Lines<ComposedChart.Line>, the rate. It inherits the chart’s curveType and reveal, so bars and line arrive as one figure rather than as two animations on two clocks.
Column highlightenableHoverHighlight dims every mark outside the hovered column, driven by the chart’s own onMouseMove index rather than by each mark’s hover — which is what makes a bar and a line in the same column light together.
Brush and toolbar<ComposedChart.Brush> in the container footer and <ComposedChart.Toolbar> above the plot. They drive one window, so a brushed range and a zoomed range cannot disagree about what is on screen.
Hidden data tableThe sr-only table of the FULL data rather than of the brushed window, so a reader on the table is never shown less than the CSV export holds. hideDataTable removes it, and zero rows render nothing.

Best practices

Do

  • Index two measures to a common base — both as a percentage of January, say — when they do not share a scale. That is the substitute for the second axis this component deliberately does not have.
  • Compose <ComposedChart.Legend> above two marks. A bar and a line at --series-1 and --series-2 differ by one step of grey and a shape, and only the shape is self-describing.
  • Set enableHoverHighlight on every mark or on none. Set on one, the hovered column dims half of itself, which reads as a rendering fault rather than as emphasis.

Don’t

  • Do not smuggle a second y-axis in through chartProps or a yAxisId on <ComposedChart.YAxis>. Recharts allows it; the component’s claim is that it does not. Two scales chosen independently let the author decide where the lines cross, which is the single most misleading thing a chart can do — and it always works, on any two series.
  • Do not assume the audio reading is here. AreaChart, BarChart and LineChart each carry a Sonify slot and this one does not, so a reader who has been listening across a dashboard falls back to the sr-only table — which is why hideDataTable is the prop not to set on this chart.

Examples

default

Bars and a line over one axis — the shape for "the volume, and the rate it moved at". One value axis, always: two measures at different scales belong in two charts, or indexed to a common base, because a second y-scale lets the author choose where the lines cross, which is the single most misleading thing a chart can do. The axis this exposes is the only one, by design.

Revenue and profit
Revenue and profit
monthRevenueProfit
Jan4,2001,800
Feb5,8002,400
Mar4,1001,600
Apr6,2002,800
May5,4002,200
Jun7,8003,400

variants

The bar half carries the same six fills as a plain BarChart and the line half the same three strokes, so a composed chart is not a third vocabulary to learn — the dot slot composes inside the line exactly as it does in LineChart. That is the reason to reach for this rather than laying two charts over each other: one config, one axis, one set of variants, and a tooltip that reports the bar and the line for the same row.

Revenue and profit
Revenue and profit
RevenueProfit
4,2001,800
5,8002,400
4,1001,600
6,2002,800
5,4002,200
7,8003,400

hover highlight

Hovering a column dims every bar outside it. The highlight reads the chart's own tooltip index, which is the half that was missing where this came from: the state existed and was cleared on leave, but nothing ever set it, so the highlight never fired. It is driven by the pointer, so it can never be the only thing carrying a reading — the clickable legend, the tooltip and the figure's hidden data table are what a keyboard reaches instead.

Revenue and profit
Revenue and profit
RevenueProfit
4,2001,800
5,8002,400
4,1001,600
6,2002,800
5,4002,200
7,8003,400

brush and loading

The two states a dashboard chart spends most of its time in, side by side. On the left, a brush over thirty days: composed as a child, and the plot above then renders only the window it selects. On the right, the same chart loading — and a brush would not appear there even if one were composed, because a brush is suppressed while isLoading is on: there is nothing yet to choose a window from.

Revenue and profit
Revenue and profit
dayRevenueProfit
D13,2002,700
D24,3782,644
D35,4262,480
D46,2292,217
D56,6991,873
D66,7831,468
D76,4731,027
D85,8031,221
D94,8461,649
D103,7082,031
D113,8862,342
D125,0052,564
D135,9242,682
D146,5442,689
D156,7962,586
D166,6522,377
D176,1282,077
D185,2821,703
D194,2061,279
D203,380968
D214,5471,411
D225,5651,822
D236,3232,176
D246,7372,450
D256,7622,628
D266,3942,699
D275,6752,658
D284,6842,507
D293,5292,257
D304,0621,922
Loading
Loading

Accessibility

  • title is required; the rows are also rendered as a visually hidden table.
  • One value axis only. A dual-axis chart lets its author choose where the lines cross, which is the single most misleading thing a chart can do.
  • enableHoverHighlight dims every bar outside the hovered column, driven by the chart’s own tooltip index.