Skip to content
Merged
Show file tree
Hide file tree
Changes from 86 commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
93bc77a
Init commit
MBilalShafi Jun 4, 2025
9ee3222
Add more cases
MBilalShafi Jun 4, 2025
f731de5
Add to a demo
MBilalShafi Jun 5, 2025
578d189
Merge branch 'master' into feature/row-grouping-dnd
MBilalShafi Jun 5, 2025
870ed69
Improve the comment
MBilalShafi Jun 13, 2025
1bc38ef
Remove unnecessary export
MBilalShafi Jun 13, 2025
511e47f
Add more use-cases
MBilalShafi Jun 24, 2025
e91ecab
Improve computation of disableDragEvents
MBilalShafi Jun 24, 2025
4f0f835
Update logic to move children instead of swapping
MBilalShafi Jun 24, 2025
f67dd82
Merge branch 'master' into feature/row-grouping-dnd
MBilalShafi Jul 14, 2025
78b546f
Merge branch 'master' into feature/row-grouping-dnd
MBilalShafi Jul 15, 2025
048462e
Merge branch 'master' into feature/row-grouping-dnd
MBilalShafi Jul 17, 2025
fef3ef0
Add a few cases + autoexpand group nodes on hover
MBilalShafi Jul 22, 2025
f9c1652
Fix reorder issues
MBilalShafi Jul 23, 2025
1577fd3
Allow move effect only
MBilalShafi Jul 23, 2025
d2b49f9
Allow to drop over drop indicator
MBilalShafi Jul 23, 2025
8eeb048
Show copy cursor for feedback
MBilalShafi Jul 23, 2025
d084c86
Reorder
MBilalShafi Jul 23, 2025
935dd13
Reorganize
MBilalShafi Jul 23, 2025
56b7dc8
Fix a couple multi-level row grouping use-cases
MBilalShafi Jul 24, 2025
b4b8343
Add first batch of test cases
MBilalShafi Jul 24, 2025
a9dec8c
Add and fix tests
MBilalShafi Jul 24, 2025
14f5f0b
Merge branch 'master' into feature/row-grouping-dnd
MBilalShafi Jul 24, 2025
e4b548a
Customize default reorder value for auto-generated (group) rows
MBilalShafi Jul 24, 2025
06719d5
Add to .gitignore
MBilalShafi Jul 24, 2025
609c128
Add another case
MBilalShafi Jul 24, 2025
54caf27
Update .gitignore
MBilalShafi Jul 24, 2025
a723172
Add more tests
MBilalShafi Jul 25, 2025
e538c2b
Add groupingValueSetter
MBilalShafi Jul 25, 2025
416cc3b
prettier
MBilalShafi Jul 25, 2025
21f65ff
Add processRowUpdate
MBilalShafi Jul 25, 2025
9a22d20
Add dataSource.editRow
MBilalShafi Jul 25, 2025
1afe0a6
Call processRowUpdate or dataSource.editRow
MBilalShafi Jul 25, 2025
1b26322
Set loading during load
MBilalShafi Jul 25, 2025
d133cda
Accommodate dataSource in auto row expand
MBilalShafi Jul 25, 2025
e88810d
docs:api
MBilalShafi Jul 25, 2025
7c32d4e
prettier
MBilalShafi Jul 25, 2025
9cb0673
Merge branch 'master' into feature/row-grouping-dnd
MBilalShafi Jul 25, 2025
e59106f
Add dataSource.setGroupKey(), a test, and a couple JSDocs
MBilalShafi Jul 28, 2025
9217f70
Add/update a few docs
MBilalShafi Jul 28, 2025
225b65a
Revert dataSource specific code
MBilalShafi Jul 28, 2025
21746db
Update test case
MBilalShafi Jul 28, 2025
1146783
docs:typescript:formatted
MBilalShafi Jul 28, 2025
5866e32
Improve the drag image styling
MBilalShafi Jul 29, 2025
9ecd8a5
Show drop indicator at adjacent positions
MBilalShafi Jul 29, 2025
1f7be68
Adjust a few styles
MBilalShafi Jul 29, 2025
06f3a49
Docs updates
MBilalShafi Jul 29, 2025
93c203b
Merge branch 'master' into feature/row-grouping-dnd
MBilalShafi Jul 29, 2025
a863742
Lint
MBilalShafi Jul 29, 2025
fcf5d17
Use updateRows to update edited row
MBilalShafi Jul 29, 2025
12db498
Update the docs
MBilalShafi Jul 29, 2025
8c847ed
Merge branch 'master' into feature/row-grouping-dnd
MBilalShafi Jul 29, 2025
453f143
Merge branch 'master' into feature/row-grouping-dnd
MBilalShafi Jul 30, 2025
fd5c78f
Update .gitignore
MBilalShafi Jul 31, 2025
ab10a29
Merge branch 'master' into feature/row-grouping-dnd
MBilalShafi Jul 31, 2025
4a32394
Merge branch 'master' into feature/row-grouping-dnd
MBilalShafi Aug 1, 2025
8adf89f
Merge branch 'master' into feature/row-grouping-dnd
MBilalShafi Aug 4, 2025
eb666bc
Andrew's review
MBilalShafi Aug 5, 2025
e9f192d
Adjust styles
MBilalShafi Aug 5, 2025
346749f
Merge branch 'master' into feature/row-grouping-dnd
MBilalShafi Aug 5, 2025
7ed2268
Fix failing test
MBilalShafi Aug 5, 2025
a97e02b
Update title
MBilalShafi Aug 5, 2025
0a24f22
Docs review addressed
MBilalShafi Aug 5, 2025
3637d97
Merge branch 'master' into feature/row-grouping-dnd
MBilalShafi Aug 11, 2025
790db7f
Add seperators for cross-parent reorders
MBilalShafi Aug 13, 2025
2e1255a
Initial (and buggy) cross parent re-order impl.
MBilalShafi Aug 14, 2025
34a8b60
Introduce validation machanism to reduce speghetti code
MBilalShafi Aug 16, 2025
7ea989e
Minor update
MBilalShafi Aug 16, 2025
142503e
setRowIndex() updated implementation
MBilalShafi Aug 17, 2025
28de358
Minor fix
MBilalShafi Aug 18, 2025
30ce5ee
Add some tests
MBilalShafi Aug 18, 2025
4dfd83a
Add more tests
MBilalShafi Aug 18, 2025
7bf8c2a
Some files reorganize and simple improvements
MBilalShafi Aug 19, 2025
71abb0d
Update docs
MBilalShafi Aug 19, 2025
1d0658d
Add warnings on onProcessRowUpdateError not defined
MBilalShafi Aug 19, 2025
0878ea1
Add paranthesis' nitpicks
MBilalShafi Aug 19, 2025
cf5e47b
🤦 - oops
MBilalShafi Aug 19, 2025
03d218e
Parenthesis
MBilalShafi Aug 19, 2025
901cb86
Merge branch 'master' into feature/row-grouping-dnd
MBilalShafi Aug 19, 2025
fe93004
Propagate totalTopLevelRowCount update for deeply nested removed nodes
MBilalShafi Aug 20, 2025
743685d
prettier
MBilalShafi Aug 20, 2025
6c16ad9
Handle group merging into existing group at a nested level
MBilalShafi Aug 20, 2025
dfba357
Reorganize the executor's logic for better readability
MBilalShafi Aug 20, 2025
8e11472
Merge branch 'master' into feature/row-grouping-dnd
MBilalShafi Aug 20, 2025
7656ec4
Improvements suggested by Andrew
MBilalShafi Aug 21, 2025
1da5aef
Merge branch 'master' into feature/row-grouping-dnd
MBilalShafi Aug 25, 2025
3ab02c0
Add destructuring
MBilalShafi Aug 25, 2025
0eaaa25
Make the reordering demo 2-level
MBilalShafi Aug 25, 2025
fccaf20
Add a few 'before' checks
MBilalShafi Aug 25, 2025
e010145
Fix auto-expand test
MBilalShafi Aug 25, 2025
07af9c8
fix decade formatting in the grouping column
cherniavskii Aug 27, 2025
9ec8bdb
docs:typescript:formatted
MBilalShafi Aug 27, 2025
2cdb036
Fix incorrect index being passed to rowOrderChange event
MBilalShafi Aug 27, 2025
7bd8a9d
Merge branch 'master' into feature/row-grouping-dnd
MBilalShafi Aug 27, 2025
218558e
Adapt the new eslint rule
MBilalShafi Aug 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# However, in order to prevent issues, editor files are ignored here.
.idea
.vscode
.cursor

__diff_output__
.DS_STORE
Expand All @@ -26,3 +27,4 @@ performance-snapshot.json
# vale downloaded config
.github/styles/
test-results
CLAUDE.md
63 changes: 63 additions & 0 deletions docs/data/data-grid/row-grouping/RowGroupingGroupingValueSetter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import * as React from 'react';
import {
DataGridPremium,
useGridApiRef,
useKeepGroupedColumnsHidden,
} from '@mui/x-data-grid-premium';
import { useMovieData } from '@mui/x-data-grid-generator';

export default function RowGroupingGroupingValueSetter() {
const data = useMovieData();
const apiRef = useGridApiRef();

const columnsWithComposer = React.useMemo(
() => [
...data.columns,
{
field: 'composer',
headerName: 'Composer',
valueGetter: (value) => value?.name,
groupingValueSetter: (value, row) => {
return {
...row,
composer: { name: value },
};
},
width: 200,
},
{
field: 'decade',
headerName: 'Decade',
valueGetter: (_, row) => (row.year ? Math.floor(row.year / 10) * 10 : null),
groupingValueSetter: (value, row) => ({
...row,
// Since converting to decade is a lossy operation, directly using the decade value should be sufficient here
year: value,
}),
valueFormatter: (value) => (value ? `${value.toString().slice(-2)}'s` : ''),
},
],
[data.columns],
);

const initialState = useKeepGroupedColumnsHidden({
apiRef,
initialState: {
rowGrouping: {
model: ['composer', 'decade'],
},
},
});

return (
<div style={{ height: 400, width: '100%' }}>
<DataGridPremium
{...data}
columns={columnsWithComposer}
apiRef={apiRef}
initialState={initialState}
rowReordering
/>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import * as React from 'react';
import {
DataGridPremium,
useGridApiRef,
GridColDef,
useKeepGroupedColumnsHidden,
} from '@mui/x-data-grid-premium';
import { useMovieData, Movie } from '@mui/x-data-grid-generator';

export default function RowGroupingGroupingValueSetter() {
const data = useMovieData();
const apiRef = useGridApiRef();

const columnsWithComposer = React.useMemo(
() => [
...data.columns,
{
field: 'composer',
headerName: 'Composer',
valueGetter: (value: { name: string }) => value?.name,
groupingValueSetter: (value, row) => {
return {
...row,
composer: { name: value },
};
},
width: 200,
} as GridColDef<Movie, string>,
{
field: 'decade',
headerName: 'Decade',
valueGetter: (_, row) => (row.year ? Math.floor(row.year / 10) * 10 : null),
groupingValueSetter: (value, row) => ({
...row,
// Since converting to decade is a lossy operation, directly using the decade value should be sufficient here
year: value,
}),
valueFormatter: (value: number | null) =>
value ? `${value.toString().slice(-2)}'s` : '',
} as GridColDef<Movie, number, string>,
],
[data.columns],
);

const initialState = useKeepGroupedColumnsHidden({
apiRef,
initialState: {
rowGrouping: {
model: ['composer', 'decade'],
},
},
});

return (
<div style={{ height: 400, width: '100%' }}>
<DataGridPremium
{...data}
columns={columnsWithComposer}
apiRef={apiRef}
initialState={initialState}
rowReordering
/>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<DataGridPremium
{...data}
columns={columnsWithComposer}
apiRef={apiRef}
initialState={initialState}
rowReordering
/>
32 changes: 32 additions & 0 deletions docs/data/data-grid/row-grouping/RowGroupingReordering.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import * as React from 'react';
import {
DataGridPremium,
useGridApiRef,
useKeepGroupedColumnsHidden,
} from '@mui/x-data-grid-premium';
import { useMovieData } from '@mui/x-data-grid-generator';

export default function RowGroupingReordering() {
const data = useMovieData();
const apiRef = useGridApiRef();

const initialState = useKeepGroupedColumnsHidden({
apiRef,
initialState: {
rowGrouping: {
model: ['company'],
},
},
});

return (
<div style={{ height: 400, width: '100%' }}>
<DataGridPremium
{...data}
apiRef={apiRef}
initialState={initialState}
rowReordering
/>
</div>
);
}
32 changes: 32 additions & 0 deletions docs/data/data-grid/row-grouping/RowGroupingReordering.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import * as React from 'react';
import {
DataGridPremium,
useGridApiRef,
useKeepGroupedColumnsHidden,
} from '@mui/x-data-grid-premium';
import { useMovieData } from '@mui/x-data-grid-generator';

export default function RowGroupingReordering() {
const data = useMovieData();
const apiRef = useGridApiRef();

const initialState = useKeepGroupedColumnsHidden({
apiRef,
initialState: {
rowGrouping: {
model: ['company'],
},
},
});

return (
<div style={{ height: 400, width: '100%' }}>
<DataGridPremium
{...data}
apiRef={apiRef}
initialState={initialState}
rowReordering
/>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<DataGridPremium
{...data}
apiRef={apiRef}
initialState={initialState}
rowReordering
/>
57 changes: 55 additions & 2 deletions docs/data/data-grid/row-grouping/row-grouping.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,10 +215,10 @@

{{"demo": "RowGroupingReadOnly.js", "bg": "inline", "defaultCodeOpen": false}}

## Using groupingValueGetter for complex grouping value
## Using groupingValueGetter() for complex grouping value

The grouping value must be either a string, a number, `null`, or `undefined`.
If your cell value is more complex, pass a `groupingValueGetter` property to the column definition to convert it into a valid value.
If your cell value is more complex, pass a `groupingValueGetter()` property to the column definition to convert it into a valid value.

```ts
const columns: GridColDef[] = [
Expand Down Expand Up @@ -377,6 +377,59 @@

:::

## Drag-and-drop group reordering

With row reordering, users can reorder row groups or move rows from one group to another.
To enable this feature with row grouping, pass the `rowReordering` prop to the Data Grid Premium component:

```tsx
<DataGridPremium rowGroupingModel={['category']} rowReordering />
```

{{"demo": "RowGroupingReordering.js", "bg": "inline", "defaultCodeOpen": false}}

### Reacting to group updates

When a row is moved from one group to another, it warrants a row update, and the row data value that was used to group this row must be updated to maintain the row grouping data integrity.

For example, in a Data Grid displaying movies grouped by companies, if the **Avatar** row is moved from **20th Century Fox** to the **Disney Studios** group, along with the row being updated in the row tree, the row data must be updated to reflect this change.

```diff
// "Avatar" row
{
title: 'Avatar',
- company: '20th Century Fox',
+ company: 'Disney Studios',
...
}
```

The Data Grid updates the internal row data, but for the change to persist on the server, you must use the [`processRowUpdate()`](/x/react-data-grid/editing/persistence/#the-processrowupdate-callback) callback.

When moving a nested group to a different parent on the same depth, there will be multiple `processRowUpdate()` calls for all the leaf descendants of the dragged group. In case some of them fail, you might see the parent node appearing in both places. Consider using the `onProcessRowUpdateError()` to show the proper feedback to the user.

Check warning on line 409 in docs/data/data-grid/row-grouping/row-grouping.md

View workflow job for this annotation

GitHub Actions / runner / vale

[vale] reported by reviewdog 🐶 [Google.Will] Avoid using 'will'. Raw Output: {"message": "[Google.Will] Avoid using 'will'.", "location": {"path": "docs/data/data-grid/row-grouping/row-grouping.md", "range": {"start": {"line": 409, "column": 75}}}, "severity": "WARNING"}

### Usage with groupingValueSetter()

If you use [`colDef.groupingValueGetter()`](#using-groupingvaluegetter-for-complex-grouping-value) to handle complex grouping values and you want to group across rows, you must use the `colDef.groupingValueSetter()` to properly convert back the simple value to the complex one.

This method should return the updated row based on the groupKey (`value`) that corresponds to the target group.

```ts
const columns: GridColDef[] = [
{
field: 'composer',
groupingValueGetter: (value) => value.name,
groupingValueSetter: (value, row) => ({
...row,
composer: { name: value },
}),
},
// ...
];
```

{{"demo": "RowGroupingGroupingValueSetter.js", "bg": "inline", "defaultCodeOpen": false}}

## Get all rows in a group

Use the `apiRef.current.getRowGroupChildren()` method to get the IDs of all rows in a group.
Expand Down
10 changes: 8 additions & 2 deletions docs/data/data-grid/row-ordering/row-ordering.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,21 @@
For now, row reordering is disabled if sorting is applied to the Data Grid.
:::

## Row reordering with tree data and grouping 🚧
## Row reordering with tree data 🚧

:::warning
This feature isn't available yet, but it is planned—you can 👍 upvote [this GitHub issue](https://github.com/mui/mui-x/issues/4821) to help us prioritize it.
This feature isn't available yet, but it is planned—you can 👍 upvote [this GitHub issue](https://github.com/mui/mui-x/issues/7774) to help us prioritize it.

Check warning on line 91 in docs/data/data-grid/row-ordering/row-ordering.md

View workflow job for this annotation

GitHub Actions / runner / vale

[vale] reported by reviewdog 🐶 [Google.We] Try to avoid using first-person plural like 'us'. Raw Output: {"message": "[Google.We] Try to avoid using first-person plural like 'us'.", "location": {"path": "docs/data/data-grid/row-ordering/row-ordering.md", "range": {"start": {"line": 91, "column": 140}}}, "severity": "WARNING"}
Please don't hesitate to leave a comment there to describe your needs, especially if you have a use case we should address or you're facing specific pain points with your current solution.
:::

With this feature, users would be able to reorder rows in use cases that also involve tree data and/or row grouping.

## Row reordering with row grouping [<span class="plan-premium"></span>](/x/introduction/licensing/#premium-plan 'Premium plan')

This feature allows users to reorder rows within grouped data to adjust the order of groups and their contents directly in the grid.

For more details, see [Row grouping—Drag-and-drop group reordering](/x/react-data-grid/row-grouping/#drag-and-drop-group-reordering).

## API

- [DataGrid](/x/api/data-grid/data-grid/)
Expand Down
6 changes: 6 additions & 0 deletions docs/data/data-grid/server-side-data/row-grouping.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,12 @@

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

## Reorder row grouping rows

:::warning
This feature isn't available yet, but it is planned—you can 👍 upvote [this GitHub issue](https://github.com/mui/mui-x/issues/18947) to help us prioritize it. Please don't hesitate to leave a comment or add some additional information.

Check warning on line 110 in docs/data/data-grid/server-side-data/row-grouping.md

View workflow job for this annotation

GitHub Actions / runner / vale

[vale] reported by reviewdog 🐶 [Google.We] Try to avoid using first-person plural like 'us'. Raw Output: {"message": "[Google.We] Try to avoid using first-person plural like 'us'.", "location": {"path": "docs/data/data-grid/server-side-data/row-grouping.md", "range": {"start": {"line": 110, "column": 141}}}, "severity": "WARNING"}
:::

## API

- [DataGrid](/x/api/data-grid/data-grid/)
Expand Down
4 changes: 4 additions & 0 deletions docs/pages/x/api/data-grid/grid-actions-col-def.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@
"type": { "description": "GridGroupingValueGetter&lt;R&gt;" },
"isPremiumPlan": true
},
"groupingValueSetter": {
"type": { "description": "GridGroupingValueSetter&lt;R&gt;" },
"isPremiumPlan": true
},
"headerAlign": { "type": { "description": "GridAlignment" } },
"headerClassName": { "type": { "description": "GridColumnHeaderClassNamePropType" } },
"headerName": { "type": { "description": "string" } },
Expand Down
4 changes: 4 additions & 0 deletions docs/pages/x/api/data-grid/grid-col-def.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@
"type": { "description": "GridGroupingValueGetter&lt;R&gt;" },
"isPremiumPlan": true
},
"groupingValueSetter": {
"type": { "description": "GridGroupingValueSetter&lt;R&gt;" },
"isPremiumPlan": true
},
"headerAlign": { "type": { "description": "GridAlignment" } },
"headerClassName": { "type": { "description": "GridColumnHeaderClassNamePropType" } },
"headerName": { "type": { "description": "string" } },
Expand Down
4 changes: 4 additions & 0 deletions docs/pages/x/api/data-grid/grid-single-select-col-def.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@
"type": { "description": "GridGroupingValueGetter&lt;R&gt;" },
"isPremiumPlan": true
},
"groupingValueSetter": {
"type": { "description": "GridGroupingValueSetter&lt;R&gt;" },
"isPremiumPlan": true
},
"headerAlign": { "type": { "description": "GridAlignment" } },
"headerClassName": { "type": { "description": "GridColumnHeaderClassNamePropType" } },
"headerName": { "type": { "description": "string" } },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -709,7 +709,7 @@
}
},
"onProcessRowUpdateError": {
"description": "Callback called when <code>processRowUpdate</code> throws an error or rejects.",
"description": "Callback called when <code>processRowUpdate()</code> throws an error or rejects.",
"typeDescriptions": { "error": { "name": "error", "description": "The error thrown." } }
},
"onPrompt": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -591,7 +591,7 @@
}
},
"onProcessRowUpdateError": {
"description": "Callback called when <code>processRowUpdate</code> throws an error or rejects.",
"description": "Callback called when <code>processRowUpdate()</code> throws an error or rejects.",
"typeDescriptions": { "error": { "name": "error", "description": "The error thrown." } }
},
"onResize": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@
}
},
"onProcessRowUpdateError": {
"description": "Callback called when <code>processRowUpdate</code> throws an error or rejects.",
"description": "Callback called when <code>processRowUpdate()</code> throws an error or rejects.",
"typeDescriptions": { "error": { "name": "error", "description": "The error thrown." } }
},
"onResize": {
Expand Down
Loading
Loading