Skip to content

Conversation

@bernardobelchior
Copy link
Member

@bernardobelchior bernardobelchior commented May 6, 2025

Part of #17557.

Add toolbar slots to all charts that render a toolbar.

This PR introduces a different way to define slots, which I'm not sure about. I'd like to hear your thoughts in this comment.

This follow-up PR contains an example on how to use the different methods: slots and render props.

@bernardobelchior bernardobelchior added type: new feature Expand the scope of the product to solve a new problem. scope: charts Changes related to the charts. labels May 6, 2025
@mui-bot
Copy link

mui-bot commented May 6, 2025

Deploy preview: https://deploy-preview-17712--material-ui-x.netlify.app/

Bundle size report

Total Size Change:${\tiny{\color{red}▲}}$+12.4KB(+0.10%) - Total Gzip Change:${\tiny{\color{red}▲}}$+4.1KB(+0.11%)
Files: 118 total (0 added, 0 removed, 17 changed)

@mui/x-charts-pro/ChartContainerProparsed:${\tiny{\color{red}▲}}$+1.27KB(+0.90%) gzip:${\tiny{\color{red}▲}}$+461B(+0.97%)
@mui/x-charts-pro/FunnelChartparsed:${\tiny{\color{red}▲}}$+1.27KB(+0.63%) gzip:${\tiny{\color{red}▲}}$+488B(+0.75%)
@mui/x-charts-pro/Heatmapparsed:${\tiny{\color{red}▲}}$+1.21KB(+0.66%) gzip:${\tiny{\color{red}▲}}$+451B(+0.75%)
@mui/x-charts-pro/ChartDataProviderProparsed:${\tiny{\color{red}▲}}$+1.2KB(+0.90%) gzip:${\tiny{\color{red}▲}}$+439B(+0.98%)
@mui/x-charts-proparsed:${\tiny{\color{red}▲}}$+1.01KB(+0.31%) gzip:${\tiny{\color{red}▲}}$+293B(+0.30%)
@mui/x-chartsparsed:${\tiny{\color{red}▲}}$+830B(+0.32%) gzip:${\tiny{\color{red}▲}}$+219B(+0.27%)
@mui/x-charts/ScatterChartparsed:${\tiny{\color{red}▲}}$+600B(+0.38%) gzip:${\tiny{\color{red}▲}}$+179B(+0.35%)
@mui/x-charts/PieChartparsed:${\tiny{\color{red}▲}}$+582B(+0.36%) gzip:${\tiny{\color{red}▲}}$+199B(+0.38%)
@mui/x-charts/LineChartparsed:${\tiny{\color{red}▲}}$+581B(+0.31%) gzip:${\tiny{\color{red}▲}}$+148B(+0.24%)
@mui/x-charts/BarChartparsed:${\tiny{\color{red}▲}}$+580B(+0.34%) gzip:${\tiny{\color{red}▲}}$+169B(+0.30%)

Show 7 more bundle changes

@mui/x-charts/RadarChartparsed:${\tiny{\color{red}▲}}$+520B(+0.33%) gzip:${\tiny{\color{red}▲}}$+196B(+0.38%)
@mui/x-charts-pro/ScatterChartProparsed:${\tiny{\color{red}▲}}$+512B(+0.27%) gzip:${\tiny{\color{red}▲}}$+136B(+0.21%)
@mui/x-charts-pro/BarChartProparsed:${\tiny{\color{red}▲}}$+492B(+0.24%) gzip:${\tiny{\color{red}▲}}$+140B(+0.21%)
@mui/x-charts-pro/LineChartProparsed:${\tiny{\color{red}▲}}$+492B(+0.22%) gzip:${\tiny{\color{red}▲}}$+136B(+0.19%)
@mui/x-charts/ChartContainerparsed:${\tiny{\color{red}▲}}$+457B(+0.41%) gzip:${\tiny{\color{red}▲}}$+149B(+0.39%)
@mui/x-charts/SparkLineChartparsed:${\tiny{\color{red}▲}}$+419B(+0.24%) gzip:${\tiny{\color{red}▲}}$+144B(+0.25%)
@mui/x-charts/ChartDataProviderparsed:${\tiny{\color{red}▲}}$+417B(+0.40%) gzip:${\tiny{\color{red}▲}}$+151B(+0.42%)

Details of bundle changes

Generated by 🚫 dangerJS against c25776e

@codspeed-hq
Copy link

codspeed-hq bot commented May 6, 2025

CodSpeed Performance Report

Merging #17712 will not alter performance

Comparing bernardobelchior:charts-slot-context (c25776e) with master (48666ad)

Summary

✅ 9 untouched benchmarks

@github-actions github-actions bot added the PR: out-of-date The pull request has merge conflicts and can't be merged. label May 6, 2025
@github-actions
Copy link

github-actions bot commented May 6, 2025

This pull request has conflicts, please resolve those before we can evaluate the pull request.

@github-actions github-actions bot removed the PR: out-of-date The pull request has merge conflicts and can't be merged. label May 6, 2025
Comment on lines +24 to +32
/**
* Slots to customize charts' components.
*/
slots?: Partial<ChartsSlots>;
/**
* The props for the slots.
*/
slotProps?: Partial<ChartsSlotProps>;
};
Copy link
Member Author

@bernardobelchior bernardobelchior May 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a break away from the current pattern of only providing slots to the higher-level chart components (e.g., LineChart) or providing slots directly to the components that render them (e.g., ChartsXAxis).

I'd like your opinion on this.

The reason I chose this option is because it allows defining the base slots (e.g., icons, buttons, tooltips) for the whole chart. This means that all toolbar components (and potentially others in the future) will use these components.

This contrasts with the current approach, which would be to pass the slots directly to the toolbar and, if using composition, to its descendants as well.

My reasoning was: if we're going to override the components using slots, might as well do it for all components in a chart. If we want to override one by one, we can use composition and the render prop if needed.

If we kept the current approach, overriding the slots when using composition would be cumbersome because we would need to set the slots in all components:

function CustomToolbar() {
  return <Toolbar>
    <ChartToolbarZoomInButton slots={{ baseIconButton: CustomButton }} />
    <ChartToolbarZoomOutButton slots={{ baseIconButton: CustomButton }} />
  </Toolbar>
}

With the approach taken in this PR, there's a single place to define the slots for base components, such as icons, buttons and tooltips.

I understand this will create two ways of using slots:

  1. The current one for all components;
  2. The new one for the toolbar.

And that's where I'd like to hear your opinion. Do you think it's better to strive for consistency in exchange for convenience? What are your thoughts?

For context, here's a PR that implements this pattern and the render prop, along with a demo to see how it looks like.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll have to sleep on the idea 😆

It seems an interesting approach, but it might be annoying to have both at the same time, as you mentioned 🤔

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JCQuintas have you slept on the idea? What did you dream about? 😛

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea of moving it to a single place, but I'm not sure it would be the best moment to do so.

I think the current idea is to still, eventually, provide a more base-ui like offering for charts, this would mean that the slots go away in favour of composition, at least in that version.

I'm not sure if having a global context for slots would make this easier or harder tbh 🤔

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I don't like the idea of having a different pattern either.

I think the current idea is to still, eventually, provide a more base-ui like offering for charts, this would mean that the slots go away in favour of composition, at least in that version.

How so? The idea of this approach is to be similar to the Data Grid approach, which is supposed to be design system agnostic.


So, concluding, you think it's better to keep the current pattern instead of introducing a new one, is that it?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to hear what @alexfauquette has to say, as he might be more informed on this

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see issues with having both strategies since they solve two distinct use-cases:

  • Direct slot propagation for big component: You want to replace the tooltip, legend, overlay. We can make it easy since their is only one of them in the chart.
  • You want to replace a MUI component: They can be multiple so the root props are propagated thanks to a context to be transparent.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was further discussed in this PR.

@bernardobelchior bernardobelchior requested a review from JCQuintas May 9, 2025 10:58
Copy link
Member

@alexfauquette alexfauquette left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm good with the idea

Comment on lines +24 to +32
/**
* Slots to customize charts' components.
*/
slots?: Partial<ChartsSlots>;
/**
* The props for the slots.
*/
slotProps?: Partial<ChartsSlotProps>;
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see issues with having both strategies since they solve two distinct use-cases:

  • Direct slot propagation for big component: You want to replace the tooltip, legend, overlay. We can make it easy since their is only one of them in the chart.
  • You want to replace a MUI component: They can be multiple so the root props are propagated thanks to a context to be transparent.

Comment on lines 21 to 22

/**
* Get the slots and slotProps from the nearest `ChartDataProvider` or `ChartDataProviderPro`.
* @returns {ChartsSlotsContextValue} The slots and slotProps from the context.
*/
export function useChartToolbarSlots<
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure it should be associated with the Toolbar.

This could be extended to all MUI components such that we can also remove the Paper, Popper, Typography.

Not sure also it should be exported, because I don't see a usage we could encourage.
The slots are here to let user the ability to override our default components.

For example slots={{ iconButton: MyCompanyButton }}

If they are at the level of creating their own component, they will either:

  • Reuse our component, but then it's transparent <ChartsDownloadButton /> The rendered button already come from the context
  • Reuse our component with render <ChartsDownloadButton render={() => <MyCompanyButton .../>}/>
  • Do their own stuff MyToolbarButton = () => Button<MyCompanyButton .../>

The only use cases if they want to have built-in way to switch from one set of components to another

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure it should be associated with the Toolbar.

Yeah, I had that doubt as well. We'll probably want to use this for more things, so I think it's better to be generic.

This could be extended to all MUI components such that we can also remove the Paper, Popper, Typography.

Good point 👍 we'll probably want to do that.

Not sure also it should be exported, because I don't see a usage we could encourage.

If we're able to set them in the ChartsDataProvider, I agree there's no point in exporting the ChartsSlotsContext. Otherwise, I think we'll need to export it so that users can replace Material components with their own when using composition.

@github-actions github-actions bot added the PR: out-of-date The pull request has merge conflicts and can't be merged. label May 20, 2025
@github-actions
Copy link

This pull request has conflicts, please resolve those before we can evaluate the pull request.

@github-actions github-actions bot removed the PR: out-of-date The pull request has merge conflicts and can't be merged. label May 21, 2025
@bernardobelchior bernardobelchior marked this pull request as ready for review May 21, 2025 08:23
@github-actions
Copy link

This pull request has conflicts, please resolve those before we can evaluate the pull request.

@github-actions github-actions bot added the PR: out-of-date The pull request has merge conflicts and can't be merged. label May 22, 2025
@github-actions github-actions bot removed the PR: out-of-date The pull request has merge conflicts and can't be merged. label May 22, 2025
Copy link
Member

@alexfauquette alexfauquette left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks nice, I'm impatient to see how this DX will evolve 👍

It might need some extra love in the documentation to avoid confusion

Comment on lines +19 to +21
ChartsAxisSlots,
ChartsToolbarSlots,
Partial<ChartsSlots> {}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it to anticipate the addition of chart export for the Funnel in an upcoming PR?

Because here you add slots that have no effect on the chart

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which slots have no effect on the funnel?

These are the toolbar's slots, can't all charts accept a toolbar, in theory?

@bernardobelchior
Copy link
Member Author

Looks nice, I'm impatient to see how this DX will evolve 👍

Thanks! Yeah, I think it'll be nice!

It might need some extra love in the documentation to avoid confusion

Yeah, I'm adding some more docs in this PR. Do you think there's still some parts that should be better documented?

@bernardobelchior bernardobelchior merged commit ea53ddc into mui:master May 26, 2025
24 checks passed
@bernardobelchior bernardobelchior deleted the charts-slot-context branch May 26, 2025 07:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

scope: charts Changes related to the charts. type: new feature Expand the scope of the product to solve a new problem.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants