MRT logoMaterial React Table

On This Page

    Editing Feature Guide

    If your tables need full CRUD functionality, you can enable editing features in Material React Table.

    There are four visually distinct editing modes to choose from, whether you want to let users edit data in a modal, inline one row at a time, one cell at a time, or just always have editing enabled for every cell.

    Relevant Props

    1
    'modal' | 'cell' | 'row' | 'table'
    'modal'
    MRT Editing Docs
    2
    boolean | (row: MRT_Row) => boolean
    MRT Editing Docs
    3
    TextFieldProps | ({ cell, column, row, table }) => TextFieldProps
    Material UI TextField Props
    4
    OnChangeFn<MRT_Cell<TData> | null>
    5
    ({ row, table }) => void
    MRT Editing Docs
    6
    OnChangeFn<MRT_Row<TData> | null>
    7
    ({ exitEditingMode, row, table, values}) => Promise<void> | void
    MRT Editing Docs

    Relevant Column Options

    1
    Array<string | { text: string; value: string }>
    2
    'text' | 'select'
    'text'
    3
    boolean | (row) => boolean
    4
    TextFieldProps | ({ cell, column, row, table }) => TextFieldProps
    Material UI TextField API

    Relevant State Options

    1
    MRT_Cell
    2
    MRT_Row

    Enable Editing

    To enable editing, you first need to set the enableEditing prop to true.

    <MaterialReactTable columns={columns} data={data} enableEditing={true} />

    However, this is just the first step. You will need to hook up logic and event listeners, but it depends on which editing mode you want to use.

    Editing Modes

    Material React Table has four supported editing modes: "modal" (default), "row", "cell" and "table". You can specify which editing mode you want to use by passing the editingMode prop.

    The "modal" editing mode opens up a dialog where the user can edit data for one row at a time. No data is saved to the table until the user clicks the save button. Clicking the cancel button clears out any changes that were made on that row.

    An onEditingRowSave callback function prop must be provided where you will get access to the updated row data so that changes can be processed and saved. It is up to you how you handle the data. This function has a exitEditingMode parameter that must be called in order to exit editing mode upon save. The reason for this is so that you can perform validation checks before letting the modal close.

    The onEditingRowSave callback function prop includes an exitEditingMode parameter that must be called in order to exit editing mode upon save. The reason for this is so that you can perform validation checks before letting the modal close.


    Demo

    Open StackblitzOpen Code SandboxOpen on GitHub
    DylanMurray261 Erdman FordEast DaphneKentucky
    RaquelKohler769 Dominic GroveColumbusOhio
    ErvinReinger566 Brakus InletSouth LindaWest Virginia
    BrittanyMcCullough722 Emie StreamLincolnNebraska
    BransonFrami32188 Larkin TurnpikeCharlestonSouth Carolina

    Rows per page

    1-5 of 5

    Source Code

    1import React, { useMemo, useState } from 'react';
    2import {
    3 MaterialReactTable,
    4 type MaterialReactTableProps,
    5 type MRT_ColumnDef,
    6} from 'material-react-table';
    7import { data, type Person } from './makeData';
    8
    9const Example = () => {
    10 const columns = useMemo<MRT_ColumnDef<Person>[]>(
    11 () => [
    12 //column definitions...
    35 ],
    36 [],
    37 );
    38
    39 const [tableData, setTableData] = useState<Person[]>(() => data);
    40
    41 const handleSaveRow: MaterialReactTableProps<Person>['onEditingRowSave'] =
    42 async ({ exitEditingMode, row, values }) => {
    43 //if using flat data and simple accessorKeys/ids, you can just do a simple assignment here.
    44 tableData[row.index] = values;
    45 //send/receive api updates here
    46 setTableData([...tableData]);
    47 exitEditingMode(); //required to exit editing mode
    48 };
    49
    50 return (
    51 <MaterialReactTable
    52 columns={columns}
    53 data={tableData}
    54 editingMode="modal" //default
    55 enableEditing
    56 onEditingRowSave={handleSaveRow}
    57 />
    58 );
    59};
    60
    61export default Example;
    62

    Row Editing Mode

    The row editing mode is an inline row editing mode. When edit mode is activated, the row shows the edit components in the data cells. No data is saved to the table until the user clicks the save button. Clicking the cancel button clears out any changes that were made on that row.

    You must provide an onEditingRowSave callback function prop where you will get access to the updated row data so that changes can be processed and saved. It is up to you how you handle the data. This function has a exitEditingMode parameter that must be called in order to exit editing mode upon save. The reason for this is so that you can perform validation checks before letting the modal close.

    The onEditingRowSave callback function prop includes an exitEditingMode parameter that must be called in order to exit editing mode upon save. The reason for this is so that you can perform validation checks before letting the modal close.


    Demo

    DylanMurray261 Erdman FordEast DaphneKentucky
    RaquelKohler769 Dominic GroveColumbusOhio
    ErvinReinger566 Brakus InletSouth LindaWest Virginia
    BrittanyMcCullough722 Emie StreamLincolnNebraska
    BransonFrami32188 Larkin TurnpikeCharlestonSouth Carolina

    Rows per page

    1-5 of 5

    Source Code

    1import React, { useMemo, useState } from 'react';
    2import {
    3 MaterialReactTable,
    4 type MaterialReactTableProps,
    5 type MRT_ColumnDef,
    6} from 'material-react-table';
    7import { data, type Person } from './makeData';
    8
    9const Example = () => {
    10 const columns = useMemo<MRT_ColumnDef<Person>[]>(
    11 () => [
    12 //column definitions...
    35 ],
    36 [],
    37 );
    38
    39 const [tableData, setTableData] = useState<Person[]>(() => data);
    40
    41 const handleSaveRow: MaterialReactTableProps<Person>['onEditingRowSave'] =
    42 async ({ exitEditingMode, row, values }) => {
    43 //if using flat data and simple accessorKeys/ids, you can just do a simple assignment here.
    44 tableData[row.index] = values;
    45 //send/receive api updates here
    46 setTableData([...tableData]);
    47 exitEditingMode(); //required to exit editing mode
    48 };
    49
    50 return (
    51 <MaterialReactTable
    52 columns={columns}
    53 data={tableData}
    54 editingMode="row"
    55 enableEditing
    56 onEditingRowSave={handleSaveRow}
    57 />
    58 );
    59};
    60
    61export default Example;
    62

    Cell Editing Mode

    The cell editing mode is a bit simpler visually. Uses double-click cells to activate editing mode, but only for that cell.

    Then there is a bit of work for you to do to wire up either the onBlur, onChange, etc., events yourself in order to save the table data. This can be done in the muiTableBodyCellEditTextFieldProps prop or column definition option.


    Demo

    DylanMurray261 Erdman FordEast DaphneKentucky
    RaquelKohler769 Dominic GroveColumbusOhio
    ErvinReinger566 Brakus InletSouth LindaWest Virginia
    BrittanyMcCullough722 Emie StreamLincolnNebraska
    BransonFrami32188 Larkin TurnpikeCharlestonSouth Carolina

    Double-Click a Cell to Edit

    Rows per page

    1-5 of 5

    Source Code

    1import React, { useMemo, useState } from 'react';
    2import {
    3 MaterialReactTable,
    4 type MRT_Cell,
    5 type MRT_ColumnDef,
    6} from 'material-react-table';
    7import { Typography } from '@mui/material';
    8import { data, type Person } from './makeData';
    9
    10const Example = () => {
    11 const columns = useMemo<MRT_ColumnDef<Person>[]>(
    12 () => [
    13 //column definitions...
    35 ],
    36 [],
    37 );
    38
    39 const [tableData, setTableData] = useState<Person[]>(() => data);
    40
    41 const handleSaveCell = (cell: MRT_Cell<Person>, value: any) => {
    42 //if using flat data and simple accessorKeys/ids, you can just do a simple assignment here
    43 tableData[cell.row.index][cell.column.id as keyof Person] = value;
    44 //send/receive api updates here
    45 setTableData([...tableData]); //re-render with new data
    46 };
    47
    48 return (
    49 <MaterialReactTable
    50 columns={columns}
    51 data={tableData}
    52 editingMode="cell"
    53 enableEditing
    54 muiTableBodyCellEditTextFieldProps={({ cell }) => ({
    55 //onBlur is more efficient, but could use onChange instead
    56 onBlur: (event) => {
    57 handleSaveCell(cell, event.target.value);
    58 },
    59 })}
    60 renderBottomToolbarCustomActions={() => (
    61 <Typography sx={{ fontStyle: 'italic', p: '0 1rem' }} variant="body2">
    62 Double-Click a Cell to Edit
    63 </Typography>
    64 )}
    65 />
    66 );
    67};
    68
    69export default Example;
    70

    Table Editing Mode

    The table editing mode is similar to the cell editing mode, but it simply has all of the data cells in the table become editable all at once.

    To save data, you must hook up the onBlur, onChange, etc., events yourself. This can be done in the muiTableBodyCellEditTextFieldProps prop or column definition option.


    Demo

    Rows per page

    1-5 of 5

    Source Code

    1import React, { useMemo, useState } from 'react';
    2import {
    3 MaterialReactTable,
    4 type MRT_Cell,
    5 type MRT_ColumnDef,
    6} from 'material-react-table';
    7import { data, type Person } from './makeData';
    8
    9const Example = () => {
    10 const columns = useMemo<MRT_ColumnDef<Person>[]>(
    11 () => [
    12 //column definitions...
    34 ],
    35 [],
    36 );
    37
    38 const [tableData, setTableData] = useState<Person[]>(() => data);
    39
    40 const handleSaveCell = (cell: MRT_Cell<Person>, value: any) => {
    41 //if using flat data and simple accessorKeys/ids, you can just do a simple assignment here
    42 tableData[cell.row.index][cell.column.id as keyof Person] = value;
    43 //send/receive api updates here
    44 setTableData([...tableData]); //re-render with new data
    45 };
    46
    47 return (
    48 <MaterialReactTable
    49 columns={columns}
    50 data={tableData}
    51 editingMode="table"
    52 enableEditing
    53 muiTableBodyCellEditTextFieldProps={({ cell }) => ({
    54 //onBlur is more efficient, but could use onChange instead
    55 onBlur: (event) => {
    56 handleSaveCell(cell, event.target.value);
    57 },
    58 variant: 'outlined',
    59 })}
    60 />
    61 );
    62};
    63
    64export default Example;
    65

    Customizing Editing Components

    You can pass any Material UI TextField Props with the muiTableBodyCellEditTextFieldProps prop.

    const columns = [
    {
    accessor: 'age',
    header: 'Age',
    muiTableBodyCellEditTextFieldProps: {
    required: true,
    type: 'number',
    variant: 'outlined',
    },
    },
    ];

    Add Validation to Editing Components

    You can add validation to the editing components by using the muiTableBodyCellEditTextFieldProps events. You can write your validation logic and hook it up to the onBlur, onChange, etc., events, then set the error and helperText props accordingly.

    If you are implementing validation, you may also need to use the onEditingRowCancel prop to clear the validation error state.

    const [validationErrors, setValidationErrors] = useState({});
    const columns = [
    {
    accessor: 'age',
    header: 'Age',
    muiTableBodyCellEditTextFieldProps: {
    error: !!validationErrors.age, //highlight mui text field red error color
    helperText: validationErrors.age, //show error message in helper text.
    required: true,
    type: 'number',
    onChange: (event) => {
    const value = event.target.value;
    //validation logic
    if (!value) {
    setValidationErrors((prev) => ({ ...prev, age: 'Age is required' }));
    } else if (value < 18) {
    setValidationErrors({
    ...validationErrors,
    age: 'Age must be 18 or older',
    });
    } else {
    delete validationErrors.age;
    setValidationErrors({ ...validationErrors });
    }
    },
    },
    },
    ];

    Use Custom Editing Components

    If you need to use a much more complicated Editing component than the built-in textfield, you can specify a custom editing component with the Edit column definition option.

    const columns = [
    {
    accessorKey: 'email',
    header: 'Email',
    Edit: ({ cell, column, table }) => <Autocomplete />,
    },
    ];

    Customize Actions/Edit Column

    You can customize the actions column in a few different ways in the displayColumnDefOptions prop's 'mrt-row-actions' section.

    <MaterialReactTable
    data={data}
    columns={columns}
    displayColumnDefOptions={{
    'mrt-row-actions': {
    header: 'Edit', //change "Actions" to "Edit"
    //use a text button instead of a icon button
    Cell: ({ row, table }) => (
    <Button onClick={() => table.setEditingRow(row)}>Edit Customer</Button>
    ),
    },
    }}
    />

    React-Hook-Form Example

    TODO