Charts
ComposedChart
Bars and lines over one axis — the volume, and the rate it moved at.
Usage
When to reach for it
Ships from@misoto22/design/charts
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
| Element | Description |
|---|---|
| Figure framerequired | ChartFigure’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 highlight | enableHoverHighlight 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 table | The 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.
| month | Revenue | Profit |
|---|---|---|
| Jan | 4,200 | 1,800 |
| Feb | 5,800 | 2,400 |
| Mar | 4,100 | 1,600 |
| Apr | 6,200 | 2,800 |
| May | 5,400 | 2,200 |
| Jun | 7,800 | 3,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 | Profit |
|---|---|
| 4,200 | 1,800 |
| 5,800 | 2,400 |
| 4,100 | 1,600 |
| 6,200 | 2,800 |
| 5,400 | 2,200 |
| 7,800 | 3,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 | Profit |
|---|---|
| 4,200 | 1,800 |
| 5,800 | 2,400 |
| 4,100 | 1,600 |
| 6,200 | 2,800 |
| 5,400 | 2,200 |
| 7,800 | 3,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.
| day | Revenue | Profit |
|---|---|---|
| D1 | 3,200 | 2,700 |
| D2 | 4,378 | 2,644 |
| D3 | 5,426 | 2,480 |
| D4 | 6,229 | 2,217 |
| D5 | 6,699 | 1,873 |
| D6 | 6,783 | 1,468 |
| D7 | 6,473 | 1,027 |
| D8 | 5,803 | 1,221 |
| D9 | 4,846 | 1,649 |
| D10 | 3,708 | 2,031 |
| D11 | 3,886 | 2,342 |
| D12 | 5,005 | 2,564 |
| D13 | 5,924 | 2,682 |
| D14 | 6,544 | 2,689 |
| D15 | 6,796 | 2,586 |
| D16 | 6,652 | 2,377 |
| D17 | 6,128 | 2,077 |
| D18 | 5,282 | 1,703 |
| D19 | 4,206 | 1,279 |
| D20 | 3,380 | 968 |
| D21 | 4,547 | 1,411 |
| D22 | 5,565 | 1,822 |
| D23 | 6,323 | 2,176 |
| D24 | 6,737 | 2,450 |
| D25 | 6,762 | 2,628 |
| D26 | 6,394 | 2,699 |
| D27 | 5,675 | 2,658 |
| D28 | 4,684 | 2,507 |
| D29 | 3,529 | 2,257 |
| D30 | 4,062 | 1,922 |
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.