Skip to content

Commit 8e898bb

Browse files
authored
[DataGrid] Allow to control the indeterminate checkbox behavior (#14247)
1 parent d8f1654 commit 8e898bb

File tree

17 files changed

+123
-1
lines changed

17 files changed

+123
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import * as React from 'react';
2+
import { DataGrid } from '@mui/x-data-grid';
3+
import { useDemoData } from '@mui/x-data-grid-generator';
4+
5+
export default function CheckboxSelectionIndeterminateGrid() {
6+
const { data } = useDemoData({
7+
dataSet: 'Commodity',
8+
rowLength: 10,
9+
maxColumns: 5,
10+
});
11+
12+
return (
13+
<div style={{ width: '100%', height: 300 }}>
14+
<DataGrid {...data} checkboxSelection indeterminateCheckboxAction="select" />
15+
</div>
16+
);
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import * as React from 'react';
2+
import { DataGrid } from '@mui/x-data-grid';
3+
import { useDemoData } from '@mui/x-data-grid-generator';
4+
5+
export default function CheckboxSelectionIndeterminateGrid() {
6+
const { data } = useDemoData({
7+
dataSet: 'Commodity',
8+
rowLength: 10,
9+
maxColumns: 5,
10+
});
11+
12+
return (
13+
<div style={{ width: '100%', height: 300 }}>
14+
<DataGrid {...data} checkboxSelection indeterminateCheckboxAction="select" />
15+
</div>
16+
);
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<DataGrid {...data} checkboxSelection indeterminateCheckboxAction="select" />

docs/data/data-grid/row-selection/row-selection.md

+7
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,13 @@ Always set the `checkboxSelection` prop to `true` even when providing a custom c
6464
Otherwise, the data grid might remove your column.
6565
:::
6666

67+
### Customize indeterminate checkbox behavior
68+
69+
The parent checkboxes (like "Select All" checkbox) when clicked in an indeterminate state will deselect the selected rows.
70+
You can customize this behavior by using the [`indeterminateCheckboxAction` prop](/x/api/data-grid/data-grid/#data-grid-prop-indeterminateCheckboxAction).
71+
72+
{{"demo": "CheckboxSelectionIndeterminateGrid.js", "bg": "inline"}}
73+
6774
### Visible rows selection [<span class="plan-pro"></span>](/x/introduction/licensing/#pro-plan 'Pro plan')
6875

6976
By default, when you click the "Select All" checkbox, all rows in the data grid are selected.

docs/pages/x/api/data-grid/data-grid-premium.json

+4
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,10 @@
181181
},
182182
"default": "false"
183183
},
184+
"indeterminateCheckboxAction": {
185+
"type": { "name": "enum", "description": "'deselect'<br>&#124;&nbsp;'select'" },
186+
"default": "\"deselect\""
187+
},
184188
"initialState": { "type": { "name": "object" } },
185189
"isCellEditable": {
186190
"type": { "name": "func" },

docs/pages/x/api/data-grid/data-grid-pro.json

+4
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,10 @@
155155
},
156156
"default": "false"
157157
},
158+
"indeterminateCheckboxAction": {
159+
"type": { "name": "enum", "description": "'deselect'<br>&#124;&nbsp;'select'" },
160+
"default": "\"deselect\""
161+
},
158162
"initialState": { "type": { "name": "object" } },
159163
"isCellEditable": {
160164
"type": { "name": "func" },

docs/pages/x/api/data-grid/data-grid.json

+4
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,10 @@
123123
},
124124
"default": "false"
125125
},
126+
"indeterminateCheckboxAction": {
127+
"type": { "name": "enum", "description": "'deselect'<br>&#124;&nbsp;'select'" },
128+
"default": "\"deselect\""
129+
},
126130
"initialState": { "type": { "name": "object" } },
127131
"isCellEditable": {
128132
"type": { "name": "func" },

docs/translations/api-docs/data-grid/data-grid-premium/data-grid-premium.json

+3
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,9 @@
202202
"ignoreValueFormatterDuringExport": {
203203
"description": "If <code>true</code>, the Data Grid will not use <code>valueFormatter</code> when exporting to CSV or copying to clipboard. If an object is provided, you can choose to ignore the <code>valueFormatter</code> for CSV export or clipboard export."
204204
},
205+
"indeterminateCheckboxAction": {
206+
"description": "If <code>select</code>, a group header checkbox in indeterminate state (like &quot;Select All&quot; checkbox) will select all the rows under it. If <code>deselect</code>, it will deselect all the rows under it. Works only if <code>checkboxSelection</code> is enabled."
207+
},
205208
"initialState": {
206209
"description": "The initial state of the DataGridPremium. The data in it is set in the state on initialization but isn&#39;t controlled. If one of the data in <code>initialState</code> is also being controlled, then the control state wins."
207210
},

docs/translations/api-docs/data-grid/data-grid-pro/data-grid-pro.json

+3
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,9 @@
183183
"ignoreValueFormatterDuringExport": {
184184
"description": "If <code>true</code>, the Data Grid will not use <code>valueFormatter</code> when exporting to CSV or copying to clipboard. If an object is provided, you can choose to ignore the <code>valueFormatter</code> for CSV export or clipboard export."
185185
},
186+
"indeterminateCheckboxAction": {
187+
"description": "If <code>select</code>, a group header checkbox in indeterminate state (like &quot;Select All&quot; checkbox) will select all the rows under it. If <code>deselect</code>, it will deselect all the rows under it. Works only if <code>checkboxSelection</code> is enabled."
188+
},
186189
"initialState": {
187190
"description": "The initial state of the DataGridPro. The data in it will be set in the state on initialization but will not be controlled. If one of the data in <code>initialState</code> is also being controlled, then the control state wins."
188191
},

docs/translations/api-docs/data-grid/data-grid/data-grid.json

+3
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@
136136
"ignoreValueFormatterDuringExport": {
137137
"description": "If <code>true</code>, the Data Grid will not use <code>valueFormatter</code> when exporting to CSV or copying to clipboard. If an object is provided, you can choose to ignore the <code>valueFormatter</code> for CSV export or clipboard export."
138138
},
139+
"indeterminateCheckboxAction": {
140+
"description": "If <code>select</code>, a group header checkbox in indeterminate state (like &quot;Select All&quot; checkbox) will select all the rows under it. If <code>deselect</code>, it will deselect all the rows under it. Works only if <code>checkboxSelection</code> is enabled."
141+
},
139142
"initialState": {
140143
"description": "The initial state of the DataGrid. The data in it will be set in the state on initialization but will not be controlled. If one of the data in <code>initialState</code> is also being controlled, then the control state wins."
141144
},

packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx

+8
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,14 @@ DataGridPremiumRaw.propTypes = {
472472
}),
473473
PropTypes.bool,
474474
]),
475+
/**
476+
* If `select`, a group header checkbox in indeterminate state (like "Select All" checkbox)
477+
* will select all the rows under it.
478+
* If `deselect`, it will deselect all the rows under it.
479+
* Works only if `checkboxSelection` is enabled.
480+
* @default "deselect"
481+
*/
482+
indeterminateCheckboxAction: PropTypes.oneOf(['deselect', 'select']),
475483
/**
476484
* The initial state of the DataGridPremium.
477485
* The data in it is set in the state on initialization but isn't controlled.

packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx

+8
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,14 @@ DataGridProRaw.propTypes = {
427427
}),
428428
PropTypes.bool,
429429
]),
430+
/**
431+
* If `select`, a group header checkbox in indeterminate state (like "Select All" checkbox)
432+
* will select all the rows under it.
433+
* If `deselect`, it will deselect all the rows under it.
434+
* Works only if `checkboxSelection` is enabled.
435+
* @default "deselect"
436+
*/
437+
indeterminateCheckboxAction: PropTypes.oneOf(['deselect', 'select']),
430438
/**
431439
* The initial state of the DataGridPro.
432440
* The data in it will be set in the state on initialization but will not be controlled.

packages/x-data-grid/src/DataGrid/DataGrid.tsx

+8
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,14 @@ DataGridRaw.propTypes = {
354354
}),
355355
PropTypes.bool,
356356
]),
357+
/**
358+
* If `select`, a group header checkbox in indeterminate state (like "Select All" checkbox)
359+
* will select all the rows under it.
360+
* If `deselect`, it will deselect all the rows under it.
361+
* Works only if `checkboxSelection` is enabled.
362+
* @default "deselect"
363+
*/
364+
indeterminateCheckboxAction: PropTypes.oneOf(['deselect', 'select']),
357365
/**
358366
* The initial state of the DataGrid.
359367
* The data in it will be set in the state on initialization but will not be controlled.

packages/x-data-grid/src/DataGrid/useDataGridProps.ts

+2
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ export const DATA_GRID_PROPS_DEFAULT_VALUES: DataGridPropsWithDefaultValues = {
5858
hideFooterSelectedRowCount: false,
5959
ignoreDiacritics: false,
6060
ignoreValueFormatterDuringExport: false,
61+
// TODO v8: Update to 'select'
62+
indeterminateCheckboxAction: 'deselect',
6163
keepColumnPositionIfDraggedOutside: false,
6264
keepNonExistentRowsSelected: false,
6365
loading: false,

packages/x-data-grid/src/components/columnSelection/GridHeaderCheckbox.tsx

+6-1
Original file line numberDiff line numberDiff line change
@@ -129,11 +129,16 @@ const GridHeaderCheckbox = React.forwardRef<HTMLButtonElement, GridColumnHeaderP
129129
isChecked ? 'checkboxSelectionUnselectAllRows' : 'checkboxSelectionSelectAllRows',
130130
);
131131

132+
const checked =
133+
rootProps.indeterminateCheckboxAction === 'select'
134+
? isChecked && !isIndeterminate
135+
: isChecked;
136+
132137
return (
133138
<rootProps.slots.baseCheckbox
134139
ref={ref}
135140
indeterminate={isIndeterminate}
136-
checked={isChecked}
141+
checked={checked}
137142
onChange={handleChange}
138143
className={classes.root}
139144
inputProps={{ 'aria-label': label }}

packages/x-data-grid/src/models/props/DataGridProps.ts

+8
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,14 @@ export interface DataGridPropsWithDefaultValues<R extends GridValidRowModel = an
244244
* @default false
245245
*/
246246
ignoreDiacritics: boolean;
247+
/**
248+
* If `select`, a group header checkbox in indeterminate state (like "Select All" checkbox)
249+
* will select all the rows under it.
250+
* If `deselect`, it will deselect all the rows under it.
251+
* Works only if `checkboxSelection` is enabled.
252+
* @default "deselect"
253+
*/
254+
indeterminateCheckboxAction: 'select' | 'deselect';
247255
/**
248256
* If `true`, the selection model will retain selected rows that do not exist.
249257
* Useful when using server side pagination and row selections need to be retained

packages/x-data-grid/src/tests/rowSelection.DataGrid.test.tsx

+20
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,26 @@ describe('<DataGrid /> - Row selection', () => {
407407
});
408408
expect(grid('selectedRowCount')?.textContent).to.equal('1 row selected');
409409
});
410+
411+
describe('prop: indeterminateCheckboxAction = "select"', () => {
412+
it('should select all the rows when clicking on "Select All" checkbox in indeterminate state', () => {
413+
render(<TestDataGridSelection checkboxSelection indeterminateCheckboxAction="select" />);
414+
const selectAllCheckbox = screen.getByRole('checkbox', { name: 'Select all rows' });
415+
fireEvent.click(screen.getAllByRole('checkbox', { name: /select row/i })[0]);
416+
fireEvent.click(selectAllCheckbox);
417+
expect(getSelectedRowIds()).to.deep.equal([0, 1, 2, 3]);
418+
});
419+
});
420+
421+
describe('prop: indeterminateCheckboxAction = "deselect"', () => {
422+
it('should deselect all the rows when clicking on "Select All" checkbox in indeterminate state', () => {
423+
render(<TestDataGridSelection checkboxSelection indeterminateCheckboxAction="deselect" />);
424+
const selectAllCheckbox = screen.getByRole('checkbox', { name: 'Select all rows' });
425+
fireEvent.click(screen.getAllByRole('checkbox', { name: /select row/i })[0]);
426+
fireEvent.click(selectAllCheckbox);
427+
expect(getSelectedRowIds()).to.deep.equal([]);
428+
});
429+
});
410430
});
411431

412432
describe('prop: checkboxSelection = true (multi selection), with keyboard events', () => {

0 commit comments

Comments
 (0)