Data Grid - Editing
The data grid has built-in support for cell and row editing.
Full-featured CRUD
The data grid is not only a data visualization tool. It offers built-in editing features for you to manage your data set. The following demo shows a full-featured CRUD (Create, Read, Update, Delete) typically found in enterprise applications.
Making a column editable
You can make a column editable by enabling the editable
property in its column definition.
This lets the user edit any cell from the specified columns.
For example, with the code snippet below, users can edit cells in the name
column, but not in the id
column.
<DataGrid columns={[{ field: 'id' }, { field: 'name', editable: true }]} />
The following demo shows an example of how to make all columns editable. Play with it by double-clicking or pressing Enter on any cell.
Row editing
By default, only one cell can be editable at a time. But you can let your user edit all cells in a row simultaneously.
To enable this behavior, set the editMode
prop on the Data Grid to "row"
. Note that you still need to set the editable
property in each column definition to specify which of them are editable; the same basic rules for cell editing also apply to row editing.
<DataGrid editMode="row" columns={[{ field: 'name', editable: true }]} />
The following demo illustrates how row editing works. The user can start and stop editing a row using the same actions as those provided for cell editing (e.g. double-clicking a cell).
Switching between edit and view modes
Each cell and row has two modes: edit
and view
. When in edit
mode, users can directly change the content of a cell or a row.
Start editing
When a cell is in view
mode, users can start editing a cell (or row if editMode="row"
) with any of the following actions:
Double-clicking a cell
Pressing Enter, Backspace or Delete—note that the latter two options both delete any existing content
Pressing any printable key, such as a, E, 0, or $
Calling
apiRef.current.startCellEditMode
passing the row ID and column field of the cell to be editedapiRef.current.startCellEditMode({ id: 1, field: 'name' });
Calling
apiRef.current.startRowEditMode
passing the ID of the row (only available ifeditMode="row"
).apiRef.current.startRowEditMode({ id: 1 });
Stop editing
When a cell is in edit
mode, the user can stop editing with any of the following interactions:
Pressing Escape—this also reverts any changes made
Pressing Tab—this also saves any changes made
Pressing Enter—this also saves any changes made and moves the focus to the next cell in the same column
Clicking outside the cell or row—this also saves any changes made
Calling
apiRef.current.stopCellEditMode({ id, field })
passing the row ID and column field of the cell that's been editedapiRef.current.stopCellEditMode({ id: 1, field: 'name' }); // or apiRef.current.stopCellEditMode({ id: 1, field: 'name', ignoreModifications: true, // will also discard the changes made });
Calling
apiRef.current.stopRowEditMode
passing the ID of the row (only possible ifeditMode="row"
).apiRef.current.stopRowEditMode({ id: 1 }); // or apiRef.current.stopRowEditMode({ id: 1, ignoreModifications: true, // will also discard the changes made });
Disable editing of specific cells within a row
The editable
property controls which cells are editable at the column level.
You can use the isCellEditable
callback prop to define which individual cells the user can edit in a given row.
It is called with a GridCellParams
object and must return true
if the cell is editable, or false
if not.
In the following demo, only the rows with an even Age
value are editable.
The editable cells have a green background for better visibility.
Value parser and value setter
You can use the valueParser
property in the column definition to modify the value entered by the user—for example, to convert the value to a different format:
const columns: GridColDef[] = [
{
valueParser: (value: any, params: GridCellParams) => {
return value.toLowerCase();
},
},
];
You can use the valueSetter
property of the column definition to customize how the row is updated with a new value.
This lets you insert a value from a nested object.
It is called with an object containing the new cell value to be saved as well as the row that the cell belongs to.
If you are already using a valueGetter
to extract the value from a nested object, then the valueSetter
will probably also be necessary.
const columns: GridColDef[] = [
{
valueSetter: (params: GridValueSetterParams) => {
const [firstName, lastName] = params.value!.toString().split(' ');
return { ...params.row, firstName, lastName };
},
},
];
In the following demo, both the valueParser
and the valueSetter
are defined for the Full name column.
The valueParser
capitalizes the value entered, and the valueSetter
splits the value and saves it correctly into the row model:
Validation
If the column definition sets a callback for the preProcessEditCellProps
property, then it will be called each time a new value is entered into a cell from this column.
This property lets you pre-process the props that are passed to the edit component.
The preProcessEditCellProps
callback is called with an object containing the following attributes:
id
: the row IDrow
: the row model containing the value(s) of the cell or row before entering edit modeprops
: the props, containing the value after the value parser, that are passed to the edit componenthasChanged
: determines ifprops.value
is different from the last time this callback was called
Data validation is one type of pre-processing that can be done in this way.
To validate the data entered, pass a callback to preProcessEditCellProps
checking if props.value
is valid.
If the new value is invalid, set props.error
to a truthy value and return the modified props, as shown in the example below.
When the user tries to save the updated value, the change will be rejected if the error attribute is truthy (invalid).
const columns: GridColDef[] = [
{
field: 'firstName',
preProcessEditCellProps: (params: GridPreProcessEditCellProps) => {
const hasError = params.props.value.length < 3;
return { ...params.props, error: hasError };
},
},
];
The demo below contains an example of server-side data validation.
In this case, the callback returns a promise that resolves to the modified props.
Note that the value passed to props.error
is passed directly to the edit component as the error
prop.
While the promise is not resolved, the edit component will receive an isProcessingProps
prop with value equal to true
.
Controlled model
You can control the active mode using the props cellModesModel
and rowModesModel
(only works if editMode="row"
).
The cellModesModel
prop accepts an object containing the mode
(and additional options) for a given column field, in a given row, as in the following example.
The options accepted are the same available in apiRef.current.startCellEditMode
and apiRef.current.stopCellEditMode
.
// Changes the mode of field=name from row with id=1 to "edit"
<DataGrid
cellModesModel={{ 1: { name: { mode: GridCellModes.Edit } } }}
/>
// Changes the mode of field=name from row with id=1 to "view", ignoring modifications made
<DataGrid
cellModesModel={{ 1: { name: { mode: GridCellModes.View, ignoreModifications: true } } }}
/>
For row editing, the rowModesModel
props work in a similar manner.
The options accepted are the same available in apiRef.current.startRowEditMode
and apiRef.current.stopRowEditMode
.
// Changes the mode of the row with id=1 to "edit"
<DataGrid
editMode="row"
rowModesModel={{ 1: { mode: GridRowModes.Edit } }}
/>
// Changes the mode of the row with id=1 to "view", ignoring modifications made
<DataGrid
editMode="row"
rowModesModel={{ 1: { mode: GridRowModes.View, ignoreModifications: true } }}
/>
Additionally, the callback props onCellModesModelChange
and onRowModesModelChange
(only works if editMode="row"
) are available.
Use them to update the respective prop.
In the demo below, cellModesModel
is used to control the mode of selected cell using the external buttons.
For an example using row editing check the full-featured CRUD component.
apiRef
The grid exposes a set of methods that enables all of these features using the imperative apiRef
. To know more about how to use it, check the API Object section.
getCellMode()
Gets the mode of a cell.
Signature:
getCellMode: (id: GridRowId, field: string) => GridCellMode
getRowMode()
Gets the mode of a row.
Signature:
getRowMode: (id: GridRowId) => GridRowMode
getRowWithUpdatedValues()
Returns the row with the values that were set by editing the cells.
In row editing, field
is ignored and all fields are considered.
Signature:
getRowWithUpdatedValues: (id: GridRowId, field: string) => GridRowModel
isCellEditable()
Controls if a cell is editable.
Signature:
isCellEditable: (params: GridCellParams) => boolean
setEditCellValue()
Sets the value of the edit cell. Commonly used inside the edit cell component.
Signature:
setEditCellValue: (params: GridEditCellValueParams, event?: MuiBaseEvent) => Promise<boolean> | void
startCellEditMode()
Puts the cell corresponding to the given row id and field into edit mode.
Signature:
startCellEditMode: (params: GridStartCellEditModeParams) => void
startRowEditMode()
Puts the row corresponding to the given id into edit mode.
Signature:
startRowEditMode: (params: GridStartRowEditModeParams) => void
stopCellEditMode()
Puts the cell corresponding to the given row id and field into view mode and updates the original row with the new value stored.
If params.ignoreModifications
is false
it will discard the modifications made.
Signature:
stopCellEditMode: (params: GridStopCellEditModeParams) => void
stopRowEditMode()
Puts the row corresponding to the given id and into view mode and updates the original row with the new values stored.
If params.ignoreModifications
is false
it will discard the modifications made.
Signature:
stopRowEditMode: (params: GridStopRowEditModeParams) => void