@mui/x-virtualizer 1.0.0-alpha.1 β†’ 1.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,356 @@
1
1
  # Changelog
2
2
 
3
+ ## 9.0.0-beta.0
4
+
5
+ <!-- generated comparing v9.0.0-alpha.4..master -->
6
+
7
+ _Mar 27, 2026_
8
+
9
+ We'd like to extend a big thank you to the 10 contributors who made this release possible. Here are some highlights ✨:
10
+
11
+ - πŸ”Š New Charts voiceover component for improved screen reader support
12
+ - ⌨️ Charts keyboard navigation improvements: axis tooltip now shows when navigating with the keyboard
13
+ - πŸ“Š Charts axes now can be set to automatically resize to fit their content
14
+ - πŸ“ New `rowCheckbox` slot in Data Grid for easier checkbox column customization
15
+ - ⚑️ `fetchRows()` API in Data Grid Pro now defaults `start` and `end` based on scroll position with lazy loading
16
+ - 🐞 Bugfixes and internal improvements
17
+
18
+ The following team members contributed to this release:
19
+ @aemartos, @alexfauquette, @arminmeh, @cherniavskii, @Janpot, @JCQuintas, @mapache-salvaje, @michelengelen, @noraleonte, @rita-codes
20
+
21
+ ### Data Grid
22
+
23
+ #### `@mui/x-data-grid@9.0.0-beta.0`
24
+
25
+ - [DataGrid] Add `rowCheckbox` slot for easier customization (#21797) @michelengelen
26
+ - [DataGrid] Prevent repeated `hasScrollbar` state updates (#21820) @arminmeh
27
+
28
+ #### `@mui/x-data-grid-pro@9.0.0-beta.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
29
+
30
+ Same changes as in `@mui/x-data-grid@9.0.0-beta.0`, plus:
31
+
32
+ - [DataGridPro] `fetchRows()` API's default `start` and `end` params based on scroll position with lazy loading (#21742) @arminmeh
33
+
34
+ #### `@mui/x-data-grid-premium@9.0.0-beta.0` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link 'Premium plan')
35
+
36
+ Same changes as in `@mui/x-data-grid-pro@9.0.0-beta.0`.
37
+
38
+ ### Date and Time Pickers
39
+
40
+ #### `@mui/x-date-pickers@9.0.0-beta.0`
41
+
42
+ Internal changes.
43
+
44
+ #### `@mui/x-date-pickers-pro@9.0.0-beta.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
45
+
46
+ Same changes as in `@mui/x-date-pickers@9.0.0-beta.0`.
47
+
48
+ ### Charts
49
+
50
+ #### `@mui/x-charts@9.0.0-beta.0`
51
+
52
+ - [charts] Add `className` prop to Pro chart plot components (#21793) @JCQuintas
53
+ - [charts] Add experimental position-based pointer interaction for line series (#21809) @JCQuintas
54
+ - [charts] Add l10n to the bar accessibility (#21815) @alexfauquette
55
+ - [charts] Add localization for the basic charts (#21822) @alexfauquette
56
+ - [charts] Add voiceover component (#21344) @alexfauquette
57
+ - [charts] Allow axes to automatically resize to content (#21087) @JCQuintas
58
+ - [charts] Document multiple use-cases for references (#21768) @alexfauquette
59
+ - [charts] Remove compatibility layer for React vs native events (#21780) @JCQuintas
60
+ - [charts] Remove deprecated `barLabel` props (#21783) @alexfauquette
61
+ - [charts] Show axis tooltip when navigating with keyboard (#21689) @Copilot
62
+
63
+ #### `@mui/x-charts-pro@9.0.0-beta.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
64
+
65
+ Same changes as in `@mui/x-charts@9.0.0-beta.0`.
66
+
67
+ #### `@mui/x-charts-premium@9.0.0-beta.0` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link 'Premium plan')
68
+
69
+ Same changes as in `@mui/x-charts-pro@9.0.0-beta.0`.
70
+
71
+ ### Tree View
72
+
73
+ #### `@mui/x-tree-view@9.0.0-alpha.4`
74
+
75
+ Internal changes.
76
+
77
+ #### `@mui/x-tree-view-pro@9.0.0-alpha.4` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
78
+
79
+ Same changes as in `@mui/x-tree-view@9.0.0-alpha.4`.
80
+
81
+ ### Codemod
82
+
83
+ #### `@mui/x-codemod@9.0.0-alpha.4`
84
+
85
+ Internal changes.
86
+
87
+ ### Docs
88
+
89
+ - [docs] Document how to customize voiceover announcement (#21833) @alexfauquette
90
+ - [docs] Remove Discord mention from docs (#21855) @mapache-salvaje
91
+ - [docs] Remove stabilized experimental feature from demo (#21869) @JCQuintas
92
+ - [docs] Update telemetry guide to reflect pseudonymous data collection and license compliance (#21812) @aemartos
93
+ - [docs] Revise the Sparkline doc (#21614) @mapache-salvaje
94
+ - [docs] Revise the Gauge doc (#21673) @mapache-salvaje
95
+ - [docs] Revise the Heatmap doc (#21676) @mapache-salvaje
96
+
97
+ ### Core
98
+
99
+ - [code-infra] Remove unused deps and unify es-toolkit via catalog (#21840) @Janpot
100
+ - [code-infra] Update @mui/internal-bundle-size-checker to canary.68 (#21836) @Janpot
101
+ - [code-infra] Update next (#21837) @Janpot
102
+ - [internal] Remove headless data grid packages (#21843) @cherniavskii
103
+
104
+ ### Miscellaneous
105
+
106
+ - Add @romgrk to CODEOWNERS for `x-virtualizer` and `x-internals` (#21819) @Copilot
107
+ - [x-license] add 2022 plan version (#21814) @aemartos
108
+
109
+ ## 9.0.0-alpha.4
110
+
111
+ _Mar 19, 2026_
112
+
113
+ We'd like to extend a big thank you to the 12 contributors who made this release possible. Here are some highlights ✨:
114
+
115
+ - 🐞 Bugfixes and internal improvements
116
+
117
+ The following team members contributed to this release:
118
+ @aemartos, @alexfauquette, @bernardobelchior, @Janpot, @JCQuintas, @LukasTy, @mapache-salvaje, @michelengelen, @noraleonte, @rita-codes, @sai6855, @siriwatknp
119
+
120
+ ### Data Grid
121
+
122
+ #### `@mui/x-data-grid@9.0.0-alpha.4`
123
+
124
+ - [DataGrid] Mark charts integration as stable (#21764) @JCQuintas
125
+ - [DataGrid] Move `elementOverrides` to constants and remove duplicates (#21618) @sai6855
126
+ - [DataGrid] Migrate from deprecated MaterialΒ UI APIs (#21682) @siriwatknp
127
+
128
+ #### `@mui/x-data-grid-pro@9.0.0-alpha.4` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
129
+
130
+ Same changes as in `@mui/x-data-grid@9.0.0-alpha.4`.
131
+
132
+ #### `@mui/x-data-grid-premium@9.0.0-alpha.4` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link 'Premium plan')
133
+
134
+ Same changes as in `@mui/x-data-grid-pro@9.0.0-alpha.4`.
135
+
136
+ ### Date and Time Pickers
137
+
138
+ #### `@mui/x-date-pickers@9.0.0-alpha.4`
139
+
140
+ - [pickers] Avoid stealing focus on click away (#13434) @LukasTy
141
+ - [pickers] Promote `fieldRef` to stable and add `clearValue` method (#21655) @michelengelen
142
+
143
+ #### `@mui/x-date-pickers-pro@9.0.0-alpha.4` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
144
+
145
+ Same changes as in `@mui/x-date-pickers@9.0.0-alpha.4`.
146
+
147
+ ### Charts
148
+
149
+ #### `@mui/x-charts@9.0.0-alpha.4`
150
+
151
+ - [charts] Add v9 chart series types and helper functions migration (#21009) @bernardobelchior
152
+ - [charts] Extract event listener to the layer container (#21751) @alexfauquette
153
+ - [charts] Fix WebGL print export canvas stretching (#21738) @JCQuintas
154
+ - [charts] Improve deprecation warnings (#21760) @alexfauquette
155
+ - [charts] Improve type safety in `identifierCleaner` (#21719) @bernardobelchior
156
+ - [charts] Make `preferStrictDomainInLineCharts` the default (#21744) @JCQuintas
157
+ - [charts] Move title and description to the layer container (#21757) @alexfauquette
158
+ - [charts] Refactor `FunnelChart` classes structure (#21652) @JCQuintas
159
+ - [charts] Refactor `Heatmap` classes structure (#21653) @JCQuintas
160
+ - [charts] Refactor `RadarChart` classes structure (#21650) @JCQuintas
161
+ - [charts] Refactor `SankeyChart` classes structure (#21654) @JCQuintas
162
+ - [charts] Refactor legend getters to use utility functions (#21628) @sai6855
163
+ - [charts] Remove deprecated `ChartContainer` and `ChartDataProvider` (#21777) @alexfauquette
164
+ - [charts] Remove deprecated `itemId` from `SeriesLegendItemContext` (#21788) @alexfauquette
165
+ - [charts] Remove deprecated `useMouseTracker()` (#21787) @alexfauquette
166
+ - [charts] Remove deprecated classes (#21775) @alexfauquette
167
+ - [charts] Remove deprecated props from PieArcLabel animation (#21789) @alexfauquette
168
+ - [charts] Remove get\*UtilityClass from public exports (#21769) @JCQuintas
169
+ - [charts] Remove the deprecated `disableHover` property (#21785) @alexfauquette
170
+ - [charts] Remove the deprecated `message` prop (#21784) @alexfauquette
171
+ - [charts] Remove deprecated props about voronoi (#21796) @alexfauquette
172
+ - [charts] Remove deprecated pieArcClasses (#21795) @alexfauquette
173
+ - [charts] Rename `data-series-id` by `data-series` (#21761) @alexfauquette
174
+ - [charts] Rename `voronoiMaxRadius`/`disableVoronoi` to `hitAreaRadius`/`disableHitArea` (#21750) @bernardobelchior
175
+ - [charts] Update pt-PT locale (#21296) @bernardobelchior
176
+ - [charts] Use different shape per series by default (#21713) @alexfauquette
177
+ - [charts] Add className prop to Radar components (#21794) @JCQuintas
178
+ - [charts] Add className prop to shared chart components (#21792) @JCQuintas
179
+ - [charts] Add className prop to BarPlot (#21791) @JCQuintas
180
+ - [charts] Portal tooltip into ChartsLayerContainer (#21801) @JCQuintas
181
+
182
+ #### `@mui/x-charts-pro@9.0.0-alpha.4` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
183
+
184
+ Same changes as in `@mui/x-charts@9.0.0-alpha.4`, plus:
185
+
186
+ - [charts-pro] Allow `brush` interaction to accept `requiredKeys/pointerMode` (#21716) @JCQuintas
187
+ - [charts-pro] Remove deprecated `onAxisClick` for Heatmap (#21786) @alexfauquette
188
+
189
+ #### `@mui/x-charts-premium@9.0.0-alpha.4` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link 'Premium plan')
190
+
191
+ Same changes as in `@mui/x-charts-pro@9.0.0-alpha.4`, plus:
192
+
193
+ - [charts-premium] Add candlestick chart (#21129) @bernardobelchior
194
+
195
+ ### Tree View
196
+
197
+ #### `@mui/x-tree-view@9.0.0-alpha.4`
198
+
199
+ Internal changes.
200
+
201
+ #### `@mui/x-tree-view-pro@9.0.0-alpha.4` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
202
+
203
+ Same changes as in `@mui/x-tree-view@9.0.0-alpha.4`.
204
+
205
+ ### Codemod
206
+
207
+ #### `@mui/x-codemod@9.0.0-alpha.4`
208
+
209
+ Internal changes.
210
+
211
+ ### Docs
212
+
213
+ - [docs-infra] Exclude `ServerSideLazyLoadingRevalidation` from argos (#21734) @sai6855
214
+ - [docs] Update charts v9 migration guide to include premium package (#21743) @bernardobelchior
215
+ - [docs] Update v9 migration guides to install next tag (#21741) @bernardobelchior
216
+ - [docs] Revise the Pie chart docs (#21565) @mapache-salvaje
217
+ - [docs] Revise the Bar Chart docs (#21482) @mapache-salvaje
218
+ - [docs] Removed a `console.log` from an aggregation demo (#21698) @michelengelen
219
+
220
+ ### Core
221
+
222
+ - [code-infra] Add pkg-pr-new as dev dependency (#21754) @Janpot
223
+ - [code-infra] Prevent `combiner` to have default parameters (#21707) @JCQuintas
224
+ - [code-infra] Remove CI coverage collection and upload to Codecov (#21671) @Janpot
225
+ - [internal] Remove @bernardobelchior from Charts CODEOWNERS (#21776) @Copilot
226
+
227
+ ### Miscellaneous
228
+
229
+ - [x-license] Fix process.env.MUI_VERSION not being replaced during build (#21727) @aemartos
230
+ - [x-license] Add new watermark license status message (#21720) @aemartos
231
+
232
+ ## 9.0.0-alpha.3
233
+
234
+ _Mar 12, 2026_
235
+
236
+ We'd like to extend a big thank you to the 13 contributors who made this release possible. Here are some highlights ✨:
237
+
238
+ - 🐞 Bugfixes and internal improvements
239
+
240
+ The following team members contributed to this release:
241
+ @aemartos, @alexfauquette, @bernardobelchior, @brijeshb42, @cherniavskii, @flaviendelangle, @Janpot, @JCQuintas, @MBilalShafi, @michelengelen, @rita-codes, @sai6855, @siriwatknp
242
+
243
+ ### Data Grid
244
+
245
+ #### `@mui/x-data-grid@9.0.0-alpha.3`
246
+
247
+ - [DataGrid] Fix crash when `rows` and `rowModesModel` are updated simultaneously (#21265) @michelengelen
248
+ - [DataGrid] Add missing `resizablePanelHandle` classes to `gridClasses` object (#21538) @sai6855
249
+ - [DataGrid] Refactor `headerAlign` style calls (#21541) @sai6855
250
+
251
+ #### `@mui/x-data-grid-pro@9.0.0-alpha.3` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
252
+
253
+ Same changes as in `@mui/x-data-grid@9.0.0-alpha.3`, plus:
254
+
255
+ - [DataGridPro] Add `role="presentation"` to detail panel toggle header content (#21634) @michelengelen
256
+ - [DataGridPro] Fix sorting not reflected in nested server-side data (#21619) @MBilalShafi
257
+
258
+ #### `@mui/x-data-grid-premium@9.0.0-alpha.3` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link 'Premium plan')
259
+
260
+ Same changes as in `@mui/x-data-grid-pro@9.0.0-alpha.3`.
261
+
262
+ ### Date and Time Pickers
263
+
264
+ #### `@mui/x-date-pickers@9.0.0-alpha.3`
265
+
266
+ - [pickers] Refactor `DateRangePickerDay` overrides to use a centralized `elementOverrides` object (#21426) @sai6855
267
+ - [pickers] Migrate from deprecated props for `PickersModalDialog` (#21702) @siriwatknp
268
+
269
+ #### `@mui/x-date-pickers-pro@9.0.0-alpha.3` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
270
+
271
+ Same changes as in `@mui/x-date-pickers@9.0.0-alpha.3`.
272
+
273
+ ### Charts
274
+
275
+ #### `@mui/x-charts@9.0.0-alpha.3`
276
+
277
+ - [charts] Differentiate Line Plot roots classes (#21679) @JCQuintas
278
+ - [charts] Enable keyboard navigation by default (#21675) @alexfauquette
279
+ - [charts] Fix keyboard tooltip radar (#21667) @alexfauquette
280
+ - [charts] Fix selector default parameter (#21638) @JCQuintas
281
+ - [charts] Fix tooltip blink between node and pointer anchor (#21611) @alexfauquette
282
+ - [charts] Let tooltip and legend reflect the line shape (#21475) @alexfauquette
283
+ - [charts] Refactor `BarChart` classes structure (#21601) @JCQuintas
284
+ - [charts] Refactor `LineChart` classes structure (#21648) @JCQuintas
285
+ - [charts] Refactor `ScatterChart` classes structure (#21651) @JCQuintas
286
+ - [charts] Refactor `PieChart` classes structure (#21649) @JCQuintas
287
+ - [charts] Remove batch rendering checks in highlight selectors (#21646) @bernardobelchior
288
+ - [charts] Standardize generic arg names to `SeriesType` (#21694) @alexfauquette
289
+ - [charts] Simplify highlight hooks return types (#21695) @alexfauquette
290
+
291
+ #### `@mui/x-charts-pro@9.0.0-alpha.3` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
292
+
293
+ Same changes as in `@mui/x-charts@9.0.0-alpha.3`, plus:
294
+
295
+ - [charts-pro] Fix heatmap style override from `arc` to `cell` (#21693) @Copilot
296
+ - [charts-pro] Fix image export truncated when page is zoomed out (#21685) @bernardobelchior
297
+ - [charts-pro] Speed-up heatmap cell search with an index lookup (#21130) @alexfauquette
298
+ - [charts-pro] Fix heatmap highlight not working (#21710) @Copilot
299
+
300
+ #### `@mui/x-charts-premium@9.0.0-alpha.3` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link 'Premium plan')
301
+
302
+ Same changes as in `@mui/x-charts-pro@9.0.0-alpha.3`, plus:
303
+
304
+ - [charts-premium] Re-enable WebGL tests (#21708) @bernardobelchior
305
+
306
+ ### Tree View
307
+
308
+ #### Breaking changes
309
+
310
+ - Remove `TreeViewBaseItem` type (use `TreeViewDefaultItemModelProperties` or a custom interface)
311
+ - Remove `useTreeViewApiRef` hook (use `useRichTreeViewApiRef`, `useSimpleTreeViewApiRef`, or `useRichTreeViewProApiRef`)
312
+ - Remove `status` from content slot props returned by `getContentProps()` (use `data-*` attributes; `status` on `useTreeItem` return value is unchanged)
313
+ - Remove deprecated CSS state classes from `treeItemClasses`: `expanded`, `selected`, `focused`, `disabled`, `editable`, `editing` (use `[data-expanded]`, `[data-selected]`, etc.)
314
+ - The `<RichTreeViewPro />` component has now virtualization enabled by default.
315
+ - The items used inside the `<RichTreeViewPro />` now have a default height of `32px`.
316
+ - The events of the `<RichTreeViewPro />` are now rendered as a flat list instead of a nested tree.
317
+
318
+ #### `@mui/x-tree-view@9.0.0-alpha.3`
319
+
320
+ - [tree view] Remove deprecated APIs (#21591) @flaviendelangle
321
+ - [tree view] Fix collapsed children not selected with `selectionPropagation.descendants` in `SimpleTreeView` (#21253) @flaviendelangle
322
+
323
+ #### `@mui/x-tree-view-pro@9.0.0-alpha.3` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
324
+
325
+ Same changes as in `@mui/x-tree-view@9.0.0-alpha.3`, plus:
326
+
327
+ - [RichTreeViewPro] Make the virtualization opt-out and port the layout doc from the data grid (#21461) @flaviendelangle
328
+
329
+ ### Codemod
330
+
331
+ #### `@mui/x-codemod@9.0.0-alpha.3`
332
+
333
+ Internal changes.
334
+
335
+ ### Docs
336
+
337
+ - [docs] Fix `AssistantWithDataSource` demo crashing (#21555) @sai6855
338
+ - [docs] Remove `Preview` pill from Sankey (#21623) @bernardobelchior
339
+ - [docs] Migrate internal MaterialΒ UI deprecated APIs (#21680) @siriwatknp
340
+ - [docs] Remove `New` flag on Tree View and Date and Time Pickers features released before v9 alpha (#21585) @flaviendelangle
341
+
342
+ ### Core
343
+
344
+ - [code-infra] Remove checkout step (#21688) @Janpot
345
+ - [code-infra] Fix contributor generation in changelog (#21718) @brijeshb42
346
+ - [docs-infra] Do not point to non-existent v8 subdomain (#21640) @cherniavskii
347
+
348
+ ### Miscellaneous
349
+
350
+ - [test] Add missing tests for forwarding props to filter operators in DataGrid (#21441) @siriwatknp
351
+ - [x-license] Export additional license types and constants (#21625) @aemartos
352
+ - [x-license] Refactor license verification to accept package info object and add v9 version gating (#21690) @aemartos
353
+
3
354
  ## 9.0.0-alpha.2
4
355
 
5
356
  _Mar 5, 2026_
@@ -92,7 +443,7 @@ Internal changes.
92
443
 
93
444
  - [docs] Add backticks and parentheses to all functions and hooks (DX-173) (#21496) @mapache-salvaje
94
445
  - [docs] Remove mentions of `mySvgRef` (#21559) @bernardobelchior
95
- - [docs] Update Roadmap section in the docs (#20892) @alelthomas
446
+ - [docs] Update Roadmap section in the docs (#20892) @alelthomas
96
447
  - [docs] Add tutorial and example app for aggregation with row grouping (DX-162) (#21102) @mapache-salvaje
97
448
  - [docs] Fix missing codemod docs (#21604) @JCQuintas
98
449
 
@@ -97,6 +97,21 @@ function initializeState(params) {
97
97
  }
98
98
  function useDimensions(store, params, _api) {
99
99
  const isFirstSizing = React.useRef(true);
100
+
101
+ // Vertical scrollbar oscillation detector.
102
+ // Counts consecutive hasScrollY flips that happen with no row-height change.
103
+ // After 2 flips it is certainly a layout feedback loop, so every further flip
104
+ // is forced to false (no scrollbar). The counter resets when row heights change.
105
+ // Only vertical scrollbar can oscillate because column widths are never 'auto'.
106
+ // https://github.com/mui/mui-x/issues/20539
107
+ const scrollYOscillation = React.useRef({
108
+ counter: 0,
109
+ heights: {
110
+ content: 0,
111
+ pinnedTop: 0,
112
+ pinnedBottom: 0
113
+ }
114
+ });
100
115
  const {
101
116
  layout,
102
117
  dimensions: {
@@ -130,6 +145,7 @@ function useDimensions(store, params, _api) {
130
145
  width: columnsTotalWidth,
131
146
  height: (0, _math.roundToDecimalPlaces)(rowsMeta.currentPageTotalHeight, 1)
132
147
  };
148
+ const prevDimensions = store.state.dimensions;
133
149
  let viewportOuterSize;
134
150
  let viewportInnerSize;
135
151
  let hasScrollX = false;
@@ -167,6 +183,36 @@ function useDimensions(store, params, _api) {
167
183
  hasScrollY = content.height + scrollbarSize > container.height;
168
184
  }
169
185
  }
186
+
187
+ // Detect vertical scrollbar oscillation.
188
+ // Track consecutive hasScrollY flips with no row-height change.
189
+ // Once confirmed (β‰₯ 2 flips), force hasScrollY off β€” the scrollbar is
190
+ // not genuinely needed, it is a layout feedback loop caused by stale
191
+ // rootSize or the horizontal scrollbar's height cascading.
192
+ {
193
+ const osc = scrollYOscillation.current;
194
+ const heightsChanged = rowsMeta.currentPageTotalHeight !== osc.heights.content || rowsMeta.pinnedTopRowsTotalHeight !== osc.heights.pinnedTop || rowsMeta.pinnedBottomRowsTotalHeight !== osc.heights.pinnedBottom;
195
+ if (heightsChanged) {
196
+ osc.counter = 0;
197
+ osc.heights = {
198
+ content: rowsMeta.currentPageTotalHeight,
199
+ pinnedTop: rowsMeta.pinnedTopRowsTotalHeight,
200
+ pinnedBottom: rowsMeta.pinnedBottomRowsTotalHeight
201
+ };
202
+ }
203
+ if (prevDimensions.isReady && hasScrollY !== prevDimensions.hasScrollY) {
204
+ if (!heightsChanged) {
205
+ osc.counter += 1;
206
+ }
207
+ if (osc.counter >= 2) {
208
+ hasScrollY = false;
209
+ // Recompute hasScrollX without the vertical scrollbar's width impact,
210
+ // otherwise the cascade (hasScrollY β†’ narrower viewport β†’ hasScrollX)
211
+ // keeps the horizontal scrollbar/filler alive and the root keeps resizing.
212
+ hasScrollX = hasScrollXIfNoYScrollBar;
213
+ }
214
+ }
215
+ }
170
216
  if (hasScrollY) {
171
217
  viewportInnerSize.width -= scrollbarSize;
172
218
  }
@@ -205,7 +251,6 @@ function useDimensions(store, params, _api) {
205
251
  autoHeight: params.dimensions.autoHeight,
206
252
  minimalContentHeight: params.dimensions.minimalContentHeight
207
253
  };
208
- const prevDimensions = store.state.dimensions;
209
254
  if ((0, _isDeepEqual.isDeepEqual)(prevDimensions, newDimensions)) {
210
255
  return;
211
256
  }
@@ -90,6 +90,21 @@ function initializeState(params) {
90
90
  }
91
91
  function useDimensions(store, params, _api) {
92
92
  const isFirstSizing = React.useRef(true);
93
+
94
+ // Vertical scrollbar oscillation detector.
95
+ // Counts consecutive hasScrollY flips that happen with no row-height change.
96
+ // After 2 flips it is certainly a layout feedback loop, so every further flip
97
+ // is forced to false (no scrollbar). The counter resets when row heights change.
98
+ // Only vertical scrollbar can oscillate because column widths are never 'auto'.
99
+ // https://github.com/mui/mui-x/issues/20539
100
+ const scrollYOscillation = React.useRef({
101
+ counter: 0,
102
+ heights: {
103
+ content: 0,
104
+ pinnedTop: 0,
105
+ pinnedBottom: 0
106
+ }
107
+ });
93
108
  const {
94
109
  layout,
95
110
  dimensions: {
@@ -123,6 +138,7 @@ function useDimensions(store, params, _api) {
123
138
  width: columnsTotalWidth,
124
139
  height: roundToDecimalPlaces(rowsMeta.currentPageTotalHeight, 1)
125
140
  };
141
+ const prevDimensions = store.state.dimensions;
126
142
  let viewportOuterSize;
127
143
  let viewportInnerSize;
128
144
  let hasScrollX = false;
@@ -160,6 +176,36 @@ function useDimensions(store, params, _api) {
160
176
  hasScrollY = content.height + scrollbarSize > container.height;
161
177
  }
162
178
  }
179
+
180
+ // Detect vertical scrollbar oscillation.
181
+ // Track consecutive hasScrollY flips with no row-height change.
182
+ // Once confirmed (β‰₯ 2 flips), force hasScrollY off β€” the scrollbar is
183
+ // not genuinely needed, it is a layout feedback loop caused by stale
184
+ // rootSize or the horizontal scrollbar's height cascading.
185
+ {
186
+ const osc = scrollYOscillation.current;
187
+ const heightsChanged = rowsMeta.currentPageTotalHeight !== osc.heights.content || rowsMeta.pinnedTopRowsTotalHeight !== osc.heights.pinnedTop || rowsMeta.pinnedBottomRowsTotalHeight !== osc.heights.pinnedBottom;
188
+ if (heightsChanged) {
189
+ osc.counter = 0;
190
+ osc.heights = {
191
+ content: rowsMeta.currentPageTotalHeight,
192
+ pinnedTop: rowsMeta.pinnedTopRowsTotalHeight,
193
+ pinnedBottom: rowsMeta.pinnedBottomRowsTotalHeight
194
+ };
195
+ }
196
+ if (prevDimensions.isReady && hasScrollY !== prevDimensions.hasScrollY) {
197
+ if (!heightsChanged) {
198
+ osc.counter += 1;
199
+ }
200
+ if (osc.counter >= 2) {
201
+ hasScrollY = false;
202
+ // Recompute hasScrollX without the vertical scrollbar's width impact,
203
+ // otherwise the cascade (hasScrollY β†’ narrower viewport β†’ hasScrollX)
204
+ // keeps the horizontal scrollbar/filler alive and the root keeps resizing.
205
+ hasScrollX = hasScrollXIfNoYScrollBar;
206
+ }
207
+ }
208
+ }
163
209
  if (hasScrollY) {
164
210
  viewportInnerSize.width -= scrollbarSize;
165
211
  }
@@ -198,7 +244,6 @@ function useDimensions(store, params, _api) {
198
244
  autoHeight: params.dimensions.autoHeight,
199
245
  minimalContentHeight: params.dimensions.minimalContentHeight
200
246
  };
201
- const prevDimensions = store.state.dimensions;
202
247
  if (isDeepEqual(prevDimensions, newDimensions)) {
203
248
  return;
204
249
  }
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mui/x-virtualizer v1.0.0-alpha.1
2
+ * @mui/x-virtualizer v1.0.0-beta.1
3
3
  *
4
4
  * @license MIT
5
5
  * This source code is licensed under the MIT license found in the
package/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mui/x-virtualizer v1.0.0-alpha.1
2
+ * @mui/x-virtualizer v1.0.0-beta.1
3
3
  *
4
4
  * @license MIT
5
5
  * This source code is licensed under the MIT license found in the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mui/x-virtualizer",
3
- "version": "1.0.0-alpha.1",
3
+ "version": "1.0.0-beta.1",
4
4
  "author": "MUI Team",
5
5
  "description": "MUI virtualization library",
6
6
  "license": "MIT",
@@ -29,7 +29,7 @@
29
29
  "dependencies": {
30
30
  "@babel/runtime": "^7.28.6",
31
31
  "@mui/utils": "^7.3.7",
32
- "@mui/x-internals": "9.0.0-alpha.2"
32
+ "@mui/x-internals": "9.0.0-alpha.4"
33
33
  },
34
34
  "peerDependencies": {
35
35
  "react": "^17.0.0 || ^18.0.0 || ^19.0.0",