Skip to content

[charts-pro] Add range buttons to toolbar#21964

Merged
JCQuintas merged 30 commits into
mui:masterfrom
JCQuintas:range-buttons
Apr 14, 2026
Merged

[charts-pro] Add range buttons to toolbar#21964
JCQuintas merged 30 commits into
mui:masterfrom
JCQuintas:range-buttons

Conversation

@JCQuintas
Copy link
Copy Markdown
Member

@JCQuintas JCQuintas commented Apr 1, 2026

Summary

  • Adds range buttons feature to the charts toolbar, allowing users to quickly zoom to predefined ranges.
  • Works with both time-series and ordinal (band/point) axes. For ordinal axes with date-like data, calendar intervals and absolute date ranges are matched against data values automatically.
  • Range buttons render as a ToggleButtonGroup with visual active state that clears when the user manually zooms/pans. The reset (null) button appears selected on initial render when zoom is at full range.
  • Supports calendar intervals ({ unit: 'month', step: 3 }), absolute date ranges ([Date, Date]), custom functions with axis context ({ scaleType, data, domain, zoomed }), and null (reset).
  • Adds baseToggleButton and baseToggleButtonGroup slots.
  • Adds ChartsToolbarRangeButtonTrigger component for custom toolbar composition.
  • Adds rangeButtons and rangeButtonsAxisId props to ChartsToolbarPro.
  • Adds RangeButtonFunctionParams type export for typing custom function values.
  • Uses RangeButtonGroup styled component (MuiChartsToolbarRangeButtons) for toolbar button styling.
  • Demos use the existing gdpPerCapitaEvolution dataset and include an ordinal axis example with monthly dates on a band axis.

@JCQuintas JCQuintas self-assigned this Apr 1, 2026
@JCQuintas JCQuintas added type: new feature Expand the scope of the product to solve a new problem. plan: Pro Impact at least one Pro user. scope: charts Changes related to the charts. labels Apr 1, 2026
@JCQuintas JCQuintas changed the title [charts] Add range buttons to toolbar [charts-pro] Add range buttons to toolbar Apr 1, 2026
@mui-bot
Copy link
Copy Markdown

mui-bot commented Apr 1, 2026

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

Updated pages:

Bundle size report

Bundle Parsed size Gzip size
@mui/x-data-grid 0B(0.00%) 0B(0.00%)
@mui/x-data-grid-pro 0B(0.00%) 0B(0.00%)
@mui/x-data-grid-premium 0B(0.00%) 0B(0.00%)
@mui/x-charts 🔺+130B(+0.03%) 🔺+27B(+0.02%)
@mui/x-charts-pro 🔺+3.41KB(+0.69%) 🔺+1.18KB(+0.81%)
@mui/x-charts-premium 🔺+3.39KB(+0.65%) 🔺+1.14KB(+0.74%)
@mui/x-date-pickers 0B(0.00%) 0B(0.00%)
@mui/x-date-pickers-pro 0B(0.00%) 0B(0.00%)
@mui/x-tree-view 0B(0.00%) 0B(0.00%)
@mui/x-tree-view-pro 0B(0.00%) 0B(0.00%)

Details of bundle changes

Generated by 🚫 dangerJS against 315c237

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Apr 1, 2026

Merging this PR will not alter performance

✅ 14 untouched benchmarks


Comparing JCQuintas:range-buttons (6df7846) with master (e0ac9c6)1

Open in CodSpeed

Footnotes

  1. No successful run was found on master (60ff5a7) during the generation of this report, so e0ac9c6 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@JCQuintas JCQuintas marked this pull request as ready for review April 2, 2026 14:23
@JCQuintas JCQuintas requested a review from alexfauquette as a code owner April 2, 2026 14:23
@JCQuintas
Copy link
Copy Markdown
Member Author

This touches generic slots, so a lot of noise from scripts too. I'll add them once we agree on api.

Copy link
Copy Markdown
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.

The API look nice. But the real value would be for candle stick so with ordinal scale.

We can either go forward wit this PR (I would give a second look at the internal logic) and we add ordinal scale management latter. Or we add it in this PR. As you prefer

Comment thread docs/data/charts/toolbar/ChartsToolbarCustomRangeButtons.tsx Outdated
Comment thread docs/data/charts/toolbar/ChartsToolbarCustomRangeButtons.tsx Outdated
Comment thread docs/data/charts/toolbar/ChartsToolbarCustomRangeButtons.tsx Outdated
Comment thread docs/data/charts/toolbar/ChartsToolbarCustomRangeButtons.tsx Outdated
Comment thread packages/x-charts-pro/src/ChartsToolbarPro/ChartsToolbarRangeButtonTrigger.tsx Outdated
Copy link
Copy Markdown
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 wonderineg if we should handle non-date. It feels a bit weird to handle that edge case.

About performances. You're looping multiple time on data arrays. to transform them into timestamp, and to find bounds. Might be better to do a binary search and get timestamp directly during the search (this can be a follow up)

Comment thread packages/x-charts/src/internals/material/index.ts Outdated
Comment thread packages/x-charts/src/models/slots/chartsBaseSlots.ts
params.zoomInteractionConfig,
optionsLookup,
),
activeRangeButtonKey: null,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

For a follow up: a initialRangeKey props could be nice

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Why?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Same usecase as initialZoom props

For example, you open the page. By default it's zoomed to the last 3 months, and you see in the toolbar that "3 months" is selected.

Without initialRangeKey users can set an initial zoom, but have no way to let the end-user know which one it is

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Ah, I think we can eventually reverse-match

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

we can eventually reverse-match

I though about it, but the tradeoff between the complexity to handle all the edge cases versus the value it bring is not that good

Comment thread packages/x-charts-pro/src/ChartsToolbarPro/rangeButtonValueToZoom.ts Outdated
Comment thread packages/x-charts-pro/src/ChartsToolbarPro/rangeButtonValueToZoom.ts Outdated
expect(result.end).to.be.closeTo((2 / 3) * 100, 0.1);
});

it('should fall back to continuous logic for non-date-like data', () => {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

SHould this at least raise a warning?

Comment on lines +267 to +271
it('should work with date strings', () => {
const result = rangeButtonValueToZoom([new Date(2024, 3, 1), new Date(2024, 6, 1)], {
scaleType: 'band',
data: ['2024-01-01', '2024-04-01', '2024-07-01', '2024-10-01'],
domain: { min: 0, max: 3 },
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Could you add a test case with a missing date?

Comment thread packages/x-charts-pro/src/ChartsToolbarPro/rangeButtonValueToZoom.ts Outdated
Copy link
Copy Markdown
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.

🎉

Thanks for not committing the generated files, it made the PR much easier :)

return (
<LineChartPro
dataset={dataset}
xAxis={[{ scaleType: 'time', dataKey: 'date', zoom: true, tickNumber: 5 }]}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You also need a y-axis to modify it's width or format the values

Image

Comment on lines +128 to +132
<span>
<ChartsToolbarZoomInTrigger render={<ToolbarButton size="small" />}>
<ZoomInIcon fontSize="small" {...slotProps.zoomInIcon} />
</ChartsToolbarZoomInTrigger>
</span>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why do you need those span?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

when the button is disabled the tooltip warns in the console that it can't work on a disabled element or smthing like that.

// When no button has been clicked and zoom is at full range, the null-value button is active.
const isActive =
activeRangeButtonKey === label ||
(activeRangeButtonKey === null && value === null && canZoomOut);
Copy link
Copy Markdown
Member

@alexfauquette alexfauquette Apr 14, 2026

Choose a reason for hiding this comment

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

This line looks weird, because the selector name is not correct.

canZoomOut is set to true when "the chart can not zoom out"

But that's outside of this PR context

@JCQuintas JCQuintas enabled auto-merge (squash) April 14, 2026 12:21
@code-infra-dashboard
Copy link
Copy Markdown

code-infra-dashboard Bot commented Apr 14, 2026

Bundle size

Bundle Parsed size Gzip size
@mui/x-data-grid 0B(0.00%) 0B(0.00%)
@mui/x-data-grid-pro 0B(0.00%) 0B(0.00%)
@mui/x-data-grid-premium 0B(0.00%) 0B(0.00%)
@mui/x-charts 🔺+130B(+0.03%) 🔺+52B(+0.05%)
@mui/x-charts-pro 🔺+3.41KB(+0.69%) 🔺+1.18KB(+0.81%)
@mui/x-charts-premium 🔺+3.39KB(+0.65%) 🔺+1.14KB(+0.74%)
@mui/x-date-pickers 0B(0.00%) 0B(0.00%)
@mui/x-date-pickers-pro 0B(0.00%) 0B(0.00%)
@mui/x-tree-view 0B(0.00%) 0B(0.00%)
@mui/x-tree-view-pro 0B(0.00%) 0B(0.00%)

Details of bundle changes

Deploy preview


Check out the code infra dashboard for more information about this PR.

@JCQuintas JCQuintas merged commit e4a4da5 into mui:master Apr 14, 2026
22 checks passed
@JCQuintas JCQuintas deleted the range-buttons branch April 14, 2026 14:57
arminmeh pushed a commit to arminmeh/mui-x that referenced this pull request Apr 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

plan: Pro Impact at least one Pro user. 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.

3 participants