What happens
<Legend> renders as an absolute overlay pinned to the top of the chart:
<div className="pointer-events-none absolute inset-x-0 top-0 flex flex-wrap gap-3 px-1">
With more than ~3 entries (or a narrow card), flex-wrap pushes entries onto a second/third row — and those rows sit on top of the plot, colliding with the fill and axis area. How many rows you get depends on card width, so a chart that looks fine at one viewport overlaps at another.
Repro
Six-entry config (e.g. a six-slice donut) inside a max-w-md card:
<PieChart data={data} config={sixEntries} dataKey="v" nameKey="name" innerRadius={0.6}>
<Legend isClickable align="center" />
<Pie />
</PieChart>
At ~400px card width the legend wraps to two rows and the second row overlays the top of the donut. Compensating with a larger margins.top only works for one specific width — the wrap count changes as the card resizes.
Workaround we ship
An in-flow "block legend" rendered as a sibling of the chart, fed by the same config (it needs no chart context — just names, labels, and seedOfColor for the swatches). Being in normal flow it can't overlap at any width, and it can carry per-entry values (e.g. allocation shares). We use the overlay <Legend> only for charts with ≤2 entries.
Possible upstream directions
- Document the ≤2–3 entry guidance on
<Legend>.
- Export a
seedOfColor-based block-legend component (or a Legend placement="block" that renders outside the overlay stack — though that likely needs the legend to escape the chart root, so a standalone component fed by config is simpler).
Happy to PR option 2 as a standalone <BlockLegend config={...} values={...}> if that direction sounds right.
What happens
<Legend>renders as an absolute overlay pinned to the top of the chart:With more than ~3 entries (or a narrow card),
flex-wrappushes entries onto a second/third row — and those rows sit on top of the plot, colliding with the fill and axis area. How many rows you get depends on card width, so a chart that looks fine at one viewport overlaps at another.Repro
Six-entry config (e.g. a six-slice donut) inside a
max-w-mdcard:At ~400px card width the legend wraps to two rows and the second row overlays the top of the donut. Compensating with a larger
margins.toponly works for one specific width — the wrap count changes as the card resizes.Workaround we ship
An in-flow "block legend" rendered as a sibling of the chart, fed by the same
config(it needs no chart context — just names, labels, andseedOfColorfor the swatches). Being in normal flow it can't overlap at any width, and it can carry per-entry values (e.g. allocation shares). We use the overlay<Legend>only for charts with ≤2 entries.Possible upstream directions
<Legend>.seedOfColor-based block-legend component (or aLegend placement="block"that renders outside the overlay stack — though that likely needs the legend to escape the chart root, so a standalone component fed byconfigis simpler).Happy to PR option 2 as a standalone
<BlockLegend config={...} values={...}>if that direction sounds right.