Data Grid - Editing
The data grid has built-in edit capabilities that you can customize to your needs.
Cell editing
Cell editing allows editing the value of one cell at a time.
Set the editable
property in the GridColDef
object to true
to allow editing cells of this column.
<DataGrid columns={[{ field: 'name', editable: true }]} />
Start editing
If a cell is editable and has focus, any of the following interactions will start the edit mode:
A Enter keydown
A Backspace or Delete keydown. It will also delete the value and stops the edit mode instantly.
A keydown of any printable key, for instance
a
,E
,0
, or$
A double click on the cell
A call to
apiRef.current.setCellMode(id, field, 'edit')
./** * Set the cellMode of a cell. * @param GridRowId * @param string * @param 'edit' | 'view' */ setCellMode: (id: GridRowId, field: string, mode: GridCellMode) => void;
Stop editing
If a cell is in edit mode and has focus, any of the following interactions will stop the edit mode:
- A Escape keydown. It will also roll back changes done in the value of the cell.
- A Tab keydown. It will also save and goes to the next cell on the same row.
- A Enter keydown. It will also save and goes to the next cell on the same column.
- A mousedown outside the cell
- A call to
apiRef.current.setCellMode(id, field, 'view')
.
Control cell editability
In addition to the editable
flag on columns, control which cell is editable using the isCellEditable
prop.
In this demo, only the rows with an even Age
value are editable.
The editable cells have a green background for better visibility.
<DataGrid
rows={rows}
columns={columns}
isCellEditable={(params) => params.row.age % 2 === 0}
/>
Controlled editing
The editRowsModel
prop lets you control the editing state.
You can handle the onEditRowsModelChange
callback to control the GridEditRowsModel
state.
Saving nested structures
If you are using a valueGetter
to extract the value from a nested object, then a valueSetter
also needs to be provided.
The first one receives the row object and must return the value to be displayed in the cell.
In the other side, the second one does the inverse, receiving the new value entered and returning the updated row.
The following demo shows how these two functions can be used:
<DataGrid rows={defaultRows} columns={columns} />
Calling the
valueSetter
is the last step in the saving process. The validation will still be called with the values before they pass through the setter.
Client-side validation
To validate the value in the cells, first add a preProcessEditCellProps
callback to the column definition of the field to validate.
Once it is called, validate the value provided in params.props.value
.
Then, return a new object contaning params.props
and also the error
attribute set to true or false.
If the error
attribute is true, the value will never be committed.
const columns: GridColDef[] = [
{
field: 'firstName',
preProcessEditCellProps: (params: GridPreProcessEditCellProps) => {
const hasError = params.props.value.length < 3;
return { ...params.props, error: hasError };
},
},
];
Here is an example implementing an email validation:
<DataGrid rows={rows} columns={columns} />
Alternatively, you can use the
GridEditRowsModel
state mentioned in the Controlled editing section. However, one limitation of this approach is that it does not work with thesingleSelect
column type.
Server-side validation
Server-side validation works like client-side validation.
The only difference is that when preProcessEditCellProps
is called, a promise must be returned.
Once the value is validated in the server, the promise should be resolved with a new object containing the error
attribute set to true or false.
The grid will wait for the promise to be resolved before exiting the edit mode.
By default,
preProcessEditCellProps
is called on each value change and during commit. With column types that automatically commit the value after a selection (e.g.singleSelect
) this means that the callback will be called twice and with the wrong value in the second call. To avoid this inconsistency, enable thepreventCommitWhileValidating
flag available in the experimental features.<DataGrid experimentalFeatures={{ preventCommitWhileValidating: true }} />
It's labeled as experimental because in v6 this flag will become the default behavior.
This demo shows how you can validate a username asynchronously and prevent the user from committing the value while validating.
It's using DataGridPro
but the same approach can be used with DataGrid
.
Server-side persistence
If you want to send the updated data to your server, you can use the onCellEditCommit
which is fired just before committing the new cell value to the grid.
You can then decide if you want to send the whole row or only the modified fields.
Custom edit component
To customize the edit component of a column, use the renderEditCell
attribute available in the GridColDef
.
The demo lets you edit the ratings by double-clicking the cell.
Edit using external button
You can override the default start editing triggers using the event.defaultMuiPrevented
on the synthetic React events.
Events
The editing feature leverages the event capability of the grid and the apiRef. The following events can be imported and used to customize the edition:
cellEditStart
: emitted when the cell turns to edit mode.cellEditStop
: emitted when the cell turns back to view mode.cellEditCommit
: emitted when the new value is committed.editCellPropsChange
: emitted when the props passed to the edit cell component are changed.
Catching events can be used to add a callback after an event while ignoring its triggers.
The demo shows how to catch the start & end edit events to log which cell is editing in an info message:
<div style={{ height: 180, width: '100%' }}>
<DataGridPro rows={rows} columns={columns} apiRef={apiRef} />
</div>
{message && (
<Alert severity="info" style={{ marginTop: 8 }}>
{message}
</Alert>
)}
Row editing
Row editing allows to edit all the cells of a row at once.
It is based on the cell editing, thus most of the features are also supported.
To enable it, change the edit mode to "row"
using the editMode
prop, then set to true
the editable
property in the GridColDef
object of those columns that should be editable.
<DataGrid editMode="row" columns={[{ field: 'name', editable: true }]} />
Start editing
If a cell is editable and has focus, any of the following interactions will start the edit mode of the corresponding row:
A Enter keydown
A double click on the cell
A call to
apiRef.current.setRowMode(id, 'edit')
./** * Sets the mode of a row. * @param {GridRowId} id The id of the row. * @param {GridRowMode} mode Can be: `"edit"`, `"view"`. */ setRowMode: (id: GridRowId, mode: GridRowMode) => void;
Stop editing
If a row is in edit mode and one of its cells is focused, any of the following interactions will stop the edit mode:
- A Escape keydown. It will also roll back changes done in the row.
- A Enter keydown. It will also save and goes to the cell at the next row at the same column.
- A mouse click outside the row
- A call to
apiRef.current.setRowMode(id, 'view')
.
Controlled editing
The editRowsModel
prop lets you control the editing state.
You can handle the onEditRowsModelChange
callback to control the GridEditRowsModel
state.
Conditional validation
Having all cells of a row in edit mode allows validating a field based on the value of another one.
To accomplish that, start by adding the preProcessEditCellProps
as explained in the cell editing.
When the callback is called, use the API to check the value of the other field and decide if the current value is valid or not.
Return a new object contaning params.props
and the error
attribute with the validation status.
Once at the least one field has the error
attribute equals to true no new value will be committed.
Note: For server-side validation, the same approach from the cell editing can be used. The data grid will wait for all promises to resolve before commiting.
The following demo requires a value for the "Payment method" column if the "Is paid?" column was checked.
The conditional validation can also be implemented with the controlled editing. This approach can be used in the free version of the DataGrid. The only limitation is that it does not work with the
singleSelect
column type.
Control with external buttons
You can disable the default behavior of the grid and control the row edit using external buttons.
Here is shown how a full-featured CRUD can be created.
<DataGridPro
rows={rows}
columns={columns}
apiRef={apiRef}
editMode="row"
onRowEditStart={handleRowEditStart}
onRowEditStop={handleRowEditStop}
onCellFocusOut={handleCellFocusOut}
components={{
Toolbar: EditToolbar,
}}
componentsProps={{
toolbar: { apiRef },
}}
/>
Saving rows with nested structures
Saving columns that make use of valueGetter
can be done adding a valueSetter
.
The same approach from the cell editing mode can be used here.
Note that the valueSetter
will be called for each field.
Server-side persistence
If you want to send the updated data to your server, you can use the onRowEditCommit
which is fired just before committing the new cell value to the grid.
To access the new values for the row, use apiRef.current.getEditRowsModel
to get all rows in edit mode, then use the id provided to get only the values for the row that was committed.
You can then decide if you want to send the whole row or only the modified fields, by checking them against the previous row values.
Events
The following events can be imported and used to customize the row edition:
rowEditStart
: emitted when the row turns to edit mode.rowEditStop
: emitted when the row turns back to view mode.rowEditCommit
: emitted when the new row values are committed.editCellPropsChange
: emitted when the props passed to an edit cell component are changed.
apiRef
⚠️ Only use this API as the last option. Give preference to the props to control the grid.
commitCellChange()
Updates the field at the given id with the value stored in the edit row model.
Signature:
commitCellChange: (params: GridCommitCellChangeParams, event?: MuiBaseEvent) => boolean | Promise<boolean>
commitRowChange()
Updates the row at the given id with the values stored in the edit row model.
Signature:
commitRowChange: (id: GridRowId, event?: MuiBaseEvent) => boolean | Promise<boolean>
getCellMode()
Gets the mode of a cell.
Signature:
getCellMode: (id: GridRowId, field: string) => GridCellMode
getEditRowsModel()
Gets the edit rows model of the grid.
Signature:
getEditRowsModel: () => GridEditRowsModel
getRowMode()
Gets the mode of a row.
Signature:
getRowMode: (id: GridRowId) => GridRowMode
isCellEditable()
Controls if a cell is editable.
Signature:
isCellEditable: (params: GridCellParams) => boolean
setCellMode()
Sets the mode of a cell.
Signature:
setCellMode: (id: GridRowId, field: string, mode: GridCellMode) => void
setEditCellValue()
Sets the value of the edit cell. Commonly used inside the edit cell component.
Signature:
setEditCellValue: (params: GridEditCellValueParams, event?: MuiBaseEvent) => Promise<boolean> | void
setEditRowsModel()
Set the edit rows model of the grid.
Signature:
setEditRowsModel: (model: GridEditRowsModel) => void
setRowMode()
Sets the mode of a row.
Signature:
setRowMode: (id: GridRowId, mode: GridRowMode) => void