Skip to content
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

[DataGrid] Support column virtualization with dynamic row height #15541

Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import * as React from 'react';
import { DataGrid } from '@mui/x-data-grid';

function useData(rowLength, columnLength) {
const [data, setData] = React.useState({ columns: [], rows: [] });

React.useEffect(() => {
const rows = [];

for (let i = 0; i < rowLength; i += 1) {
const row = {
id: i,
};

for (let j = 1; j <= columnLength; j += 1) {
row[`price${j}M`] = `${i.toString()}, ${j} `;
}

rows.push(row);
}

const columns = [];

for (let j = 1; j <= columnLength; j += 1) {
columns.push({ field: `price${j}M`, headerName: `${j}M`, width: 55 });
}

setData({
rows,
columns,
});
}, [rowLength, columnLength]);

return data;
}

export default function VirtualizeColumnsWithAutoRowHeight() {
const data = useData(100, 100);

return (
<div style={{ height: 600, width: '100%' }}>
<DataGrid
{...data}
getRowHeight={() => 'auto'}
virtualizeColumnsWithAutoRowHeight
/>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import * as React from 'react';
import { DataGrid, GridColDef, GridRowId } from '@mui/x-data-grid';

export interface DataRowModel {
id: GridRowId;
[price: string]: number | string;
}

export interface GridData {
columns: GridColDef[];
rows: DataRowModel[];
}

function useData(rowLength: number, columnLength: number) {
const [data, setData] = React.useState<GridData>({ columns: [], rows: [] });

React.useEffect(() => {
const rows: DataRowModel[] = [];

for (let i = 0; i < rowLength; i += 1) {
const row: DataRowModel = {
id: i,
};

for (let j = 1; j <= columnLength; j += 1) {
row[`price${j}M`] = `${i.toString()}, ${j} `;
}

rows.push(row);
}

const columns: GridColDef[] = [];

for (let j = 1; j <= columnLength; j += 1) {
columns.push({ field: `price${j}M`, headerName: `${j}M`, width: 55 });
}

setData({
rows,
columns,
});
}, [rowLength, columnLength]);

return data;
}

export default function VirtualizeColumnsWithAutoRowHeight() {
const data = useData(100, 100);

return (
<div style={{ height: 600, width: '100%' }}>
<DataGrid
{...data}
getRowHeight={() => 'auto'}
virtualizeColumnsWithAutoRowHeight
/>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<DataGrid
{...data}
getRowHeight={() => 'auto'}
virtualizeColumnsWithAutoRowHeight
/>
10 changes: 9 additions & 1 deletion docs/data/data-grid/row-height/row-height.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ This side effect happens because a row height estimation is used while a row is
You can configure the estimated value used by passing a function to the `getEstimatedRowHeight` prop.
If not provided, the default row height of `52px` is used as estimation.
It's recommended to pass this prop if the content deviates too much from the default value.
Note that, due to the implementation adopted, the virtualization of the columns is also disabled to force all columns to be rendered at the same time.

```tsx
<DataGrid getRowHeight={() => 'auto'} getEstimatedRowHeight={() => 200} />
Expand All @@ -78,6 +77,15 @@ Add padding to the cells to increase the space between the content and the cell

:::

### Column virtualization
cherniavskii marked this conversation as resolved.
Show resolved Hide resolved

By default, the virtualization of the columns is disabled to force all columns to be rendered at the same time and calculate the row height correctly.
cherniavskii marked this conversation as resolved.
Show resolved Hide resolved

If you need column virtualization, you can set the `virtualizeColumnsWithAutoRowHeight` prop to `true`.
With this approach, the Data Grid measures the row height based on the visible columns, and the row height might change during horizontal scrolling.
cherniavskii marked this conversation as resolved.
Show resolved Hide resolved

{{"demo": "VirtualizeColumnsWithAutoRowHeight.js", "bg": "inline" }}

## Row density

Give your users the option to change the default row density to match their preferences—compact, standard, or comfortable.
Expand Down
3 changes: 2 additions & 1 deletion docs/pages/x/api/data-grid/data-grid-premium.json
Original file line number Diff line number Diff line change
Expand Up @@ -656,7 +656,8 @@
}
},
"unstable_listView": { "type": { "name": "bool" } },
"unstable_rowSpanning": { "type": { "name": "bool" }, "default": "false" }
"unstable_rowSpanning": { "type": { "name": "bool" }, "default": "false" },
"virtualizeColumnsWithAutoRowHeight": { "type": { "name": "bool" }, "default": "false" }
},
"name": "DataGridPremium",
"imports": [
Expand Down
3 changes: 2 additions & 1 deletion docs/pages/x/api/data-grid/data-grid-pro.json
Original file line number Diff line number Diff line change
Expand Up @@ -587,7 +587,8 @@
}
},
"unstable_listView": { "type": { "name": "bool" } },
"unstable_rowSpanning": { "type": { "name": "bool" }, "default": "false" }
"unstable_rowSpanning": { "type": { "name": "bool" }, "default": "false" },
"virtualizeColumnsWithAutoRowHeight": { "type": { "name": "bool" }, "default": "false" }
},
"name": "DataGridPro",
"imports": [
Expand Down
3 changes: 2 additions & 1 deletion docs/pages/x/api/data-grid/data-grid.json
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,8 @@
},
"additionalInfo": { "sx": true }
},
"unstable_rowSpanning": { "type": { "name": "bool" }, "default": "false" }
"unstable_rowSpanning": { "type": { "name": "bool" }, "default": "false" },
"virtualizeColumnsWithAutoRowHeight": { "type": { "name": "bool" }, "default": "false" }
},
"name": "DataGrid",
"imports": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,9 @@
},
"unstable_rowSpanning": {
"description": "If <code>true</code>, the Data Grid will auto span the cells over the rows having the same value."
},
"virtualizeColumnsWithAutoRowHeight": {
"description": "If <code>true</code>, the Data Grid doesn&#39;t disable column virtualization when <code>getRowHeight</code> is set to <code>() =&gt; &#39;auto&#39;</code>. By default, column virtualization is disabled when dynamic row height is enabled to measure the row height correctly. For datasets with a large number of columns, this can cause performance issues. The downside of enabling this prop is that the row height will be estimated based the cells that are currently rendered, which can cause row height change when scrolling horizontally."
}
},
"classDescriptions": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,9 @@
},
"unstable_rowSpanning": {
"description": "If <code>true</code>, the Data Grid will auto span the cells over the rows having the same value."
},
"virtualizeColumnsWithAutoRowHeight": {
"description": "If <code>true</code>, the Data Grid doesn&#39;t disable column virtualization when <code>getRowHeight</code> is set to <code>() =&gt; &#39;auto&#39;</code>. By default, column virtualization is disabled when dynamic row height is enabled to measure the row height correctly. For datasets with a large number of columns, this can cause performance issues. The downside of enabling this prop is that the row height will be estimated based the cells that are currently rendered, which can cause row height change when scrolling horizontally."
}
},
"classDescriptions": {
Expand Down
3 changes: 3 additions & 0 deletions docs/translations/api-docs/data-grid/data-grid/data-grid.json
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,9 @@
},
"unstable_rowSpanning": {
"description": "If <code>true</code>, the Data Grid will auto span the cells over the rows having the same value."
},
"virtualizeColumnsWithAutoRowHeight": {
"description": "If <code>true</code>, the Data Grid doesn&#39;t disable column virtualization when <code>getRowHeight</code> is set to <code>() =&gt; &#39;auto&#39;</code>. By default, column virtualization is disabled when dynamic row height is enabled to measure the row height correctly. For datasets with a large number of columns, this can cause performance issues. The downside of enabling this prop is that the row height will be estimated based the cells that are currently rendered, which can cause row height change when scrolling horizontally."
}
},
"classDescriptions": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1127,6 +1127,14 @@ DataGridPremiumRaw.propTypes = {
* @default false
*/
unstable_rowSpanning: PropTypes.bool,
/**
* If `true`, the Data Grid doesn't disable column virtualization when `getRowHeight` is set to `() => 'auto'`.
* By default, column virtualization is disabled when dynamic row height is enabled to measure the row height correctly.
* For datasets with a large number of columns, this can cause performance issues.
* The downside of enabling this prop is that the row height will be estimated based the cells that are currently rendered, which can cause row height change when scrolling horizontally.
* @default false
*/
virtualizeColumnsWithAutoRowHeight: PropTypes.bool,
} as any;

interface DataGridPremiumComponent {
Expand Down
8 changes: 8 additions & 0 deletions packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1026,4 +1026,12 @@ DataGridProRaw.propTypes = {
* @default false
*/
unstable_rowSpanning: PropTypes.bool,
/**
* If `true`, the Data Grid doesn't disable column virtualization when `getRowHeight` is set to `() => 'auto'`.
* By default, column virtualization is disabled when dynamic row height is enabled to measure the row height correctly.
* For datasets with a large number of columns, this can cause performance issues.
* The downside of enabling this prop is that the row height will be estimated based the cells that are currently rendered, which can cause row height change when scrolling horizontally.
* @default false
*/
virtualizeColumnsWithAutoRowHeight: PropTypes.bool,
} as any;
8 changes: 8 additions & 0 deletions packages/x-data-grid/src/DataGrid/DataGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -821,4 +821,12 @@ DataGridRaw.propTypes = {
* @default false
*/
unstable_rowSpanning: PropTypes.bool,
/**
* If `true`, the Data Grid doesn't disable column virtualization when `getRowHeight` is set to `() => 'auto'`.
* By default, column virtualization is disabled when dynamic row height is enabled to measure the row height correctly.
* For datasets with a large number of columns, this can cause performance issues.
* The downside of enabling this prop is that the row height will be estimated based the cells that are currently rendered, which can cause row height change when scrolling horizontally.
* @default false
*/
virtualizeColumnsWithAutoRowHeight: PropTypes.bool,
} as any;
1 change: 1 addition & 0 deletions packages/x-data-grid/src/components/cell/GridCell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,7 @@ const GridCell = React.forwardRef<HTMLDivElement, GridCellProps>(function GridCe
padding: 0,
opacity: 0,
width: 0,
height: 0,
border: 0,
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,5 @@ export const DATA_GRID_PROPS_DEFAULT_VALUES: DataGridPropsWithDefaultValues = {
sortingOrder: ['asc' as const, 'desc' as const, null],
throttleRowsMs: 0,
unstable_rowSpanning: false,
virtualizeColumnsWithAutoRowHeight: false,
};
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import type {
GridRowEntry,
GridRowId,
} from '../../../models';
import { DataGridProcessedProps } from '../../../models/props/DataGridProps';
import { selectedIdsLookupSelector } from '../rowSelection/gridRowSelectionSelector';
import { gridRowsMetaSelector } from '../rows/gridRowsMetaSelector';
import { getFirstNonSpannedColumnToRender } from '../columns/gridColumnsUtils';
Expand Down Expand Up @@ -640,6 +641,7 @@ type RenderContextInputs = {
visibleColumns: ReturnType<typeof gridVisibleColumnDefinitionsSelector>;
hiddenCellsOriginMap: ReturnType<typeof gridRowSpanningHiddenCellsOriginMapSelector>;
listView: boolean;
virtualizeColumnsWithAutoRowHeight: DataGridProcessedProps['virtualizeColumnsWithAutoRowHeight'];
};

function inputsSelector(
Expand Down Expand Up @@ -677,6 +679,7 @@ function inputsSelector(
visibleColumns,
hiddenCellsOriginMap,
listView: rootProps.unstable_listView ?? false,
virtualizeColumnsWithAutoRowHeight: rootProps.virtualizeColumnsWithAutoRowHeight,
};
}

Expand Down Expand Up @@ -740,12 +743,14 @@ function computeRenderContext(
lastSize: inputs.lastRowHeight,
});

for (let i = firstRowToRender; i < lastRowToRender && !hasRowWithAutoHeight; i += 1) {
const row = inputs.rows[i];
hasRowWithAutoHeight = inputs.apiRef.current.rowHasAutoHeight(row.id);
if (!inputs.virtualizeColumnsWithAutoRowHeight) {
for (let i = firstRowToRender; i < lastRowToRender && !hasRowWithAutoHeight; i += 1) {
const row = inputs.rows[i];
hasRowWithAutoHeight = inputs.apiRef.current.rowHasAutoHeight(row.id);
}
}

if (!hasRowWithAutoHeight) {
if (!hasRowWithAutoHeight || inputs.virtualizeColumnsWithAutoRowHeight) {
firstColumnIndex = binarySearch(realLeft, inputs.columnPositions, {
atStart: true,
lastPosition: inputs.columnsTotalWidth,
Expand Down
8 changes: 8 additions & 0 deletions packages/x-data-grid/src/models/props/DataGridProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,14 @@ export interface DataGridPropsWithDefaultValues<R extends GridValidRowModel = an
* @default false
*/
unstable_rowSpanning: boolean;
/**
* If `true`, the Data Grid doesn't disable column virtualization when `getRowHeight` is set to `() => 'auto'`.
cherniavskii marked this conversation as resolved.
Show resolved Hide resolved
* By default, column virtualization is disabled when dynamic row height is enabled to measure the row height correctly.
* For datasets with a large number of columns, this can cause performance issues.
* The downside of enabling this prop is that the row height will be estimated based the cells that are currently rendered, which can cause row height change when scrolling horizontally.
Copy link
Member

Choose a reason for hiding this comment

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

Love that, giving the control of the UX tradeoff in the hands of designers.

Copy link
Member

@oliviertassinari oliviertassinari Nov 24, 2024

Choose a reason for hiding this comment

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

It looks like AG Grid doesn't support this option https://www.ag-grid.com/javascript-data-grid/row-height/#auto-row-height. Still, experiencing this https://codesandbox.io/p/sandbox/focused-rain-zxyt6p?file=%2Fdemo.js%3A21%2C35, I almost wonder if this shouldn't be the default. As a developer or Product Manager, it's easier to search for "layout shift with auto height" than "grid slow performance" 😄.

Anyway, we have this in the docs. We will see how this goes.

Copy link
Member Author

Choose a reason for hiding this comment

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

It looks like AG Grid doesn't support this option ag-grid.com/javascript-data-grid/row-height#auto-row-height.

I think they don't need it – they took an interesting approach of per-column row auto height.
So they can exclude specific columns from virtualization (i.e. always render them) if they have auto height enabled.
It's smart.

* @default false
*/
virtualizeColumnsWithAutoRowHeight: boolean;
}

/**
Expand Down