From 1d5f3ee07f32e93ad8001a76af6fd9328edb5e11 Mon Sep 17 00:00:00 2001 From: Bilal Shafi Date: Fri, 5 Jun 2026 20:55:19 +0500 Subject: [PATCH 1/3] =?UTF-8?q?=F0=9F=90=9B=20[DataGrid]=20Wait=20for=20ro?= =?UTF-8?q?ws=20before=20autosize=20on=20mount?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Delay autosizeOnMount until the initial render context is ready and committed, so fitting rows are measured before column widths are extracted. Add a browser regression test covering a wide value in the last rendered row. --- .../src/tests/columns.DataGridPro.test.tsx | 27 +++++++ .../columnResize/useGridColumnResize.tsx | 75 ++++++++++++++++++- 2 files changed, 99 insertions(+), 3 deletions(-) diff --git a/packages/x-data-grid-pro/src/tests/columns.DataGridPro.test.tsx b/packages/x-data-grid-pro/src/tests/columns.DataGridPro.test.tsx index ea435aedc6ae6..ab5c2d345fb65 100644 --- a/packages/x-data-grid-pro/src/tests/columns.DataGridPro.test.tsx +++ b/packages/x-data-grid-pro/src/tests/columns.DataGridPro.test.tsx @@ -635,6 +635,33 @@ describe(' - Columns', () => { }); }); + it('should wait for all rows to be rendered on mount when rows fit the viewport', async () => { + const autosizeRows = [ + { id: 0, brand: 'Nike' }, + { id: 1, brand: 'Adidas' }, + { id: 2, brand: 'Puma' }, + { id: 3, brand: 'Reebok' }, + { id: 4, brand: 'Asics' }, + { id: 5, brand: 'New Balance' }, + { id: 6, brand: 'Lululemon Athletica International Collection' }, + ]; + const autosizeColumns = [{ field: 'brand' }]; + + render( + , + ); + + await waitFor(() => { + const wideCell = getCell(6, 0); + expect(wideCell.scrollWidth).to.be.at.most(wideCell.clientWidth); + }); + }); + it('should work with flex columns', async () => { const { user } = render( ; type ResizeDirection = keyof typeof GridColumnHeaderSeparatorSides; +function isRenderContextReadyForAutosizeOnMount(apiRef: RefObject) { + const dimensions = gridDimensionsSelector(apiRef); + if (!dimensions.isReady) { + return false; + } + + const { rows } = gridVisibleRowsSelector(apiRef); + if (rows.length === 0) { + return true; + } + + const renderContext = gridRenderContextSelector(apiRef); + if (renderContext.lastRowIndex <= renderContext.firstRowIndex) { + return false; + } + + if (!dimensions.hasScrollY) { + return renderContext.firstRowIndex === 0 && renderContext.lastRowIndex >= rows.length; + } + + return true; +} + function trackFinger(event: any, currentTouchId: number | undefined): CursorCoordinates | boolean { if (currentTouchId !== undefined && event.changedTouches) { for (let i = 0; i < event.changedTouches.length; i += 1) { @@ -851,10 +878,52 @@ export const useGridColumnResize = ( useOnMount(() => { if (props.autosizeOnMount) { - Promise.resolve().then(() => { + let frameHandle: number | undefined; + let unsubscribeStateChange: (() => void) | undefined; + let unsubscribeRenderedRowsIntervalChange: (() => void) | undefined; + + const cleanupListeners = () => { + unsubscribeStateChange?.(); + unsubscribeRenderedRowsIntervalChange?.(); + unsubscribeStateChange = undefined; + unsubscribeRenderedRowsIntervalChange = undefined; + }; + + const runAutosize = () => { + frameHandle = undefined; + cleanupListeners(); apiRef.current.autosizeColumns(props.autosizeOptions); - }); + }; + + const scheduleAutosize = () => { + if (frameHandle === undefined) { + frameHandle = requestAnimationFrame(runAutosize); + } + }; + + const checkRenderContext = () => { + if (isRenderContextReadyForAutosizeOnMount(apiRef)) { + scheduleAutosize(); + } + }; + + unsubscribeStateChange = apiRef.current.subscribeEvent('stateChange', checkRenderContext); + unsubscribeRenderedRowsIntervalChange = apiRef.current.subscribeEvent( + 'renderedRowsIntervalChange', + checkRenderContext, + ); + + checkRenderContext(); + + return () => { + cleanupListeners(); + if (frameHandle !== undefined) { + cancelAnimationFrame(frameHandle); + } + }; } + + return undefined; }); useGridNativeEventListener( From dfd1433826e7c14aa2f6bb0d54fed8b3b31c491e Mon Sep 17 00:00:00 2001 From: Bilal Shafi Date: Fri, 5 Jun 2026 21:27:40 +0500 Subject: [PATCH 2/3] Improve the regression test --- .../src/tests/columns.DataGridPro.test.tsx | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/packages/x-data-grid-pro/src/tests/columns.DataGridPro.test.tsx b/packages/x-data-grid-pro/src/tests/columns.DataGridPro.test.tsx index ab5c2d345fb65..6023ed4aa00cf 100644 --- a/packages/x-data-grid-pro/src/tests/columns.DataGridPro.test.tsx +++ b/packages/x-data-grid-pro/src/tests/columns.DataGridPro.test.tsx @@ -1,3 +1,4 @@ +import * as React from 'react'; import { createRenderer, fireEvent, screen, act, waitFor } from '@mui/internal-test-utils'; import { spy } from 'sinon'; import { type RefObject } from '@mui/x-internals/types'; @@ -10,6 +11,7 @@ import { gridColumnFieldsSelector, type GridApi, type GridAutosizeOptions, + type GridColDef, } from '@mui/x-data-grid-pro'; import { useGridPrivateApiContext } from '@mui/x-data-grid-pro/internals'; import { getColumnHeaderCell, getCell, getRow } from 'test/utils/helperFn'; @@ -636,6 +638,23 @@ describe(' - Columns', () => { }); it('should wait for all rows to be rendered on mount when rows fit the viewport', async () => { + const shortValue = 'Nike'; + const wideValue = 'Lululemon Athletica International Collection'; + + function DeferredCellContent({ value }: { value: string }) { + const [showValue, setShowValue] = React.useState(value === shortValue); + + React.useEffect(() => { + if (!showValue) { + Promise.resolve().then(() => { + Promise.resolve().then(() => setShowValue(true)); + }); + } + }, [showValue]); + + return {showValue ? value : shortValue}; + } + const autosizeRows = [ { id: 0, brand: 'Nike' }, { id: 1, brand: 'Adidas' }, @@ -643,9 +662,14 @@ describe(' - Columns', () => { { id: 3, brand: 'Reebok' }, { id: 4, brand: 'Asics' }, { id: 5, brand: 'New Balance' }, - { id: 6, brand: 'Lululemon Athletica International Collection' }, + { id: 6, brand: wideValue }, + ]; + const autosizeColumns: GridColDef[] = [ + { + field: 'brand', + renderCell: ({ value }) => , + }, ]; - const autosizeColumns = [{ field: 'brand' }]; render( - Columns', () => { await waitFor(() => { const wideCell = getCell(6, 0); + expect(wideCell.textContent).to.equal(wideValue); expect(wideCell.scrollWidth).to.be.at.most(wideCell.clientWidth); }); }); From be063860471da199a8979328abb8fc2bb026970b Mon Sep 17 00:00:00 2001 From: Bilal Shafi Date: Fri, 5 Jun 2026 21:30:53 +0500 Subject: [PATCH 3/3] Add comment --- .../x-data-grid-pro/src/tests/columns.DataGridPro.test.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/x-data-grid-pro/src/tests/columns.DataGridPro.test.tsx b/packages/x-data-grid-pro/src/tests/columns.DataGridPro.test.tsx index 6023ed4aa00cf..74b38e042d3db 100644 --- a/packages/x-data-grid-pro/src/tests/columns.DataGridPro.test.tsx +++ b/packages/x-data-grid-pro/src/tests/columns.DataGridPro.test.tsx @@ -637,6 +637,7 @@ describe(' - Columns', () => { }); }); + // Regression test for https://github.com/mui/mui-x/issues/22505 it('should wait for all rows to be rendered on mount when rows fit the viewport', async () => { const shortValue = 'Nike'; const wideValue = 'Lululemon Athletica International Collection'; @@ -646,6 +647,8 @@ describe(' - Columns', () => { React.useEffect(() => { if (!showValue) { + // Hack to make the test fail similar to https://github.com/mui/mui-x/issues/22505 + // in our test env Promise.resolve().then(() => { Promise.resolve().then(() => setShowValue(true)); });