Skip to content

[blog][WIP] Details about charts improvements #46197

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/pages/blog/v8-charts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import * as React from 'react';
import TopLayoutBlog from 'docs/src/modules/components/TopLayoutBlog';
import { docs } from './v8-charts.md?muiMarkdown';

export default function Page() {
return <TopLayoutBlog docs={docs} />;
}
154 changes: 154 additions & 0 deletions docs/pages/blog/v8-charts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
---
title: Charts revamped
description: Check out the new features coming in v8.
date: 2025-05-31T00:00:00.000Z
authors: ['alexfauquette']
tags: ['MUI X', 'Product']
manualCard: true
---

There's a lot of exciting news in the v8 release for the charts.
All updates about v8 are already in the [release blog post](/blog/mui-x-v8/#charts).
But in this article I would like to spend more time to provide context on the main breaking changes.

Check warning on line 12 in docs/pages/blog/v8-charts.md

View workflow job for this annotation

GitHub Actions / runner / vale

[vale] reported by reviewdog 🐶 [Google.FirstPerson] Avoid first-person pronouns such as ' I '. Raw Output: {"message": "[Google.FirstPerson] Avoid first-person pronouns such as ' I '.", "location": {"path": "docs/pages/blog/v8-charts.md", "range": {"start": {"line": 12, "column": 20}}}, "severity": "WARNING"}

## A bit of context

The library is quite young.
The first version v6.0.0-alpha.0 got released two years ago.

Since that time, we added tons of features, the community got involved, with now 360k weekly downloads on npm, and a lot of issues open.

Check warning on line 19 in docs/pages/blog/v8-charts.md

View workflow job for this annotation

GitHub Actions / runner / vale

[vale] reported by reviewdog 🐶 [Google.We] Try to avoid using first-person plural like 'we'. Raw Output: {"message": "[Google.We] Try to avoid using first-person plural like 'we'.", "location": {"path": "docs/pages/blog/v8-charts.md", "range": {"start": {"line": 19, "column": 18}}}, "severity": "WARNING"}
Thanks for all that :pray:

During that time, we did nearly no breaking changes ([v7 migration guide](https://mui.com/x/migration/migration-charts-v6/) is one of our smallest migration guide).

Check warning on line 22 in docs/pages/blog/v8-charts.md

View workflow job for this annotation

GitHub Actions / runner / vale

[vale] reported by reviewdog 🐶 [Google.We] Try to avoid using first-person plural like 'our'. Raw Output: {"message": "[Google.We] Try to avoid using first-person plural like 'our'.", "location": {"path": "docs/pages/blog/v8-charts.md", "range": {"start": {"line": 22, "column": 135}}}, "severity": "WARNING"}

Check warning on line 22 in docs/pages/blog/v8-charts.md

View workflow job for this annotation

GitHub Actions / runner / vale

[vale] reported by reviewdog 🐶 [Google.We] Try to avoid using first-person plural like 'we'. Raw Output: {"message": "[Google.We] Try to avoid using first-person plural like 'we'.", "location": {"path": "docs/pages/blog/v8-charts.md", "range": {"start": {"line": 22, "column": 19}}}, "severity": "WARNING"}
So it was time to fix all my initial design mistake to improve performances and the developer experience.

Check warning on line 23 in docs/pages/blog/v8-charts.md

View workflow job for this annotation

GitHub Actions / runner / vale

[vale] reported by reviewdog 🐶 [Google.FirstPerson] Avoid first-person pronouns such as 'my'. Raw Output: {"message": "[Google.FirstPerson] Avoid first-person pronouns such as 'my'.", "location": {"path": "docs/pages/blog/v8-charts.md", "range": {"start": {"line": 23, "column": 27}}}, "severity": "WARNING"}

In this article I will present the main pain points we fixed in this v8 release.

Check warning on line 25 in docs/pages/blog/v8-charts.md

View workflow job for this annotation

GitHub Actions / runner / vale

[vale] reported by reviewdog 🐶 [Google.We] Try to avoid using first-person plural like 'we'. Raw Output: {"message": "[Google.We] Try to avoid using first-person plural like 'we'.", "location": {"path": "docs/pages/blog/v8-charts.md", "range": {"start": {"line": 25, "column": 53}}}, "severity": "WARNING"}

Check warning on line 25 in docs/pages/blog/v8-charts.md

View workflow job for this annotation

GitHub Actions / runner / vale

[vale] reported by reviewdog 🐶 [Google.Will] Avoid using 'will'. Raw Output: {"message": "[Google.Will] Avoid using 'will'.", "location": {"path": "docs/pages/blog/v8-charts.md", "range": {"start": {"line": 25, "column": 19}}}, "severity": "WARNING"}

Check warning on line 25 in docs/pages/blog/v8-charts.md

View workflow job for this annotation

GitHub Actions / runner / vale

[vale] reported by reviewdog 🐶 [Google.FirstPerson] Avoid first-person pronouns such as ' I '. Raw Output: {"message": "[Google.FirstPerson] Avoid first-person pronouns such as ' I '.", "location": {"path": "docs/pages/blog/v8-charts.md", "range": {"start": {"line": 25, "column": 16}}}, "severity": "WARNING"}
Those are mostly about how user can customize the charts:

- Customizing the legend
- Managing placement inside SVG
- Customizing the tooltip

## Custom legend

The package started with the idea to get everything in the `<svg />`.
The plotting, the axis, but also the legend, the title.

This leads to the main issue of SVG.
The text positioning.

To create a legend inside a SVG, you need to measure all your texts, and from it deduce their positions.
Here is all the positions we need to compute to display three series in a basic horizontal legend.

Check warning on line 41 in docs/pages/blog/v8-charts.md

View workflow job for this annotation

GitHub Actions / runner / vale

[vale] reported by reviewdog 🐶 [Google.We] Try to avoid using first-person plural like 'we'. Raw Output: {"message": "[Google.We] Try to avoid using first-person plural like 'we'.", "location": {"path": "docs/pages/blog/v8-charts.md", "range": {"start": {"line": 41, "column": 27}}}, "severity": "WARNING"}

<span class="only-light-mode">
<img src="/static/blog/v8-charts/svg-position.svg" style="width: 796px; margin-top: 16px; margin-bottom: 8px;" alt="Illustration of the position to compute in order to display a basic three items legend" />
</span>
<span class="only-dark-mode">
<img src="/static/blog/v8-charts/svg-position-dark.svg" style="width: 796px; margin-top: 16px; margin-bottom: 8px;" alt="Illustration of the position to compute in order to display a basic three items legend" />
</span>

Which is much more complex than writing some CSS like `display: 'flex', flexDirection: 'row'`.
In addition HTML provides out of the box the overflow management, and better hover/click mangement.

So we dropped this "Every thing as SVG" to provide an HTML legend.

Check warning on line 53 in docs/pages/blog/v8-charts.md

View workflow job for this annotation

GitHub Actions / runner / vale

[vale] reported by reviewdog 🐶 [Google.We] Try to avoid using first-person plural like 'we'. Raw Output: {"message": "[Google.We] Try to avoid using first-person plural like 'we'.", "location": {"path": "docs/pages/blog/v8-charts.md", "range": {"start": {"line": 53, "column": 4}}}, "severity": "WARNING"}

### The wrapping solution

Before v8 you got a `<ChartContainer />` that take care of managing all the data, and rendering the `<svg />` element.
Such that you could render all your chart content as follow.

```jsx
<ChartContainer>
<SVGLegend />
<BarPlot />
<ChartXAxis />
</ChartContainer>
```

Now we need the legend to be inside the data provider, but outside the SVG.
So we've splited this `<ChartContainer />` into `<ChartDataProvider />` and `<ChartSurface />` as follow.

```jsx
<ChartDataProvider>
<HTMLLegend />
<ChartSurface>
<BarPlot />
<ChartXAxis />
</ChartSurface>
</ChartDataProvider>
```

Since creating a legend with a custom design is now much easier (no need to measure text bounding boxes), we provide a hook `useLegend()` that returns all the data needed to render one.

## Placement inside SVG

In the previous section, we've seen how we removed the legend from SVG.
But that's leaves a big white space.

Initially the placement in charts was defined by a `margin` prop which defines the space between the border of SVG and the "drawing area".

<span class="only-light-mode">
<img src="/static/blog/v8-charts/margin-illustration.svg" style="width: 796px; margin-top: 16px; margin-bottom: 8px;" alt="Illustration of the position to compute in order to display a basic three items legend" />
</span>
<span class="only-dark-mode">
<img src="/static/blog/v8-charts/margin-illustration-dark.svg" style="width: 796px; margin-top: 16px; margin-bottom: 8px;" alt="Illustration of the position to compute in order to display a basic three items legend" />
</span>

So if we remove the legend, or if user chose to hide an axis, they should also update this `margin` prop.
Otherwise the chart will get plenty of empty space

<span class="only-light-mode">
<img src="/static/blog/v8-charts/remove-legend.svg" style="width: 796px; margin-top: 16px; margin-bottom: 8px;" alt="Illustration of the position to compute in order to display a basic three items legend" />
</span>
<span class="only-dark-mode">
<img src="/static/blog/v8-charts/remove-legend-dark.svg" style="width: 796px; margin-top: 16px; margin-bottom: 8px;" alt="Illustration of the position to compute in order to display a basic three items legend" />
</span>

### Axes with dimension

To simplify this management, we added a notion of axis size.
Now the drawing area is defined by the `margin` plus the x-axes' `height` and the y-axes `width`.

So when you add or hide an axis, no need to care about updating the `margin`.

<span class="only-light-mode">
<img src="/static/blog/v8-charts/axis-illustration.svg" style="width: 796px; margin-top: 16px; margin-bottom: 8px;" alt="Illustration of the position to compute in order to display a basic three items legend" />
</span>
<span class="only-dark-mode">
<img src="/static/blog/v8-charts/axis-illustration-dark.svg" style="width: 796px; margin-top: 16px; margin-bottom: 8px;" alt="Illustration of the position to compute in order to display a basic three items legend" />
</span>

In addition it's now feasible to stack axes on top of each other.

[Add a picture of the charts with multiple axes]

## Creating your own tooltip

Customizing the tooltip was a bit hard.
It was not a technical issue, but more a wrong choice of level of abstraction.

We used slots to allow modifying 3 distinct elements:

- The tooltip container that defines the position of the tooltip
- The axis tooltip content that defines the content of the tooltip when trigger by an axis value.
- The item tooltip content that defines the content of the tooltip when trigger by an specific item.

3 slots interlinked was not my best idea.
So we simplified it a lot

### One slots, multiple helpers

The v8 provides a single slots named `tooltip` and you can put hte HTML you want in it.

In addition, we provide the simpler components and helper hooks to let user compose the tooltip they want.
They can re-create the default tooltip as follow.

```jsx
<ChartTooltipWrapper>
<ChartsItemTooltip /> {/* or <ChartsAxisTooltip /> */}
</ChartTooltipWrapper>
```

User can then re-create the part they want (the wrapper or the content).

To simplify the process, we also export hooks ... that gives all the information needed to reproduce the component.
5 changes: 5 additions & 0 deletions docs/public/static/blog/v8-charts/axis-illustration-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions docs/public/static/blog/v8-charts/axis-illustration.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions docs/public/static/blog/v8-charts/margin-illustration.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions docs/public/static/blog/v8-charts/remove-legend-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions docs/public/static/blog/v8-charts/remove-legend.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions docs/public/static/blog/v8-charts/svg-position-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions docs/public/static/blog/v8-charts/svg-position.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading