React MUI v5 Data Grid Tutorial: Sort, Filter, Export, Pagination and Cell Editing

The Material-UI Data Grid is easily the largest and most customizable component in the MUI library. It has more subcomponents and props than any other component. In this tutorial I will review common features of the Data Grid: sorting, filtering, exporting, pagination, and cell editing.

I will also review the docs and some challenges I had with the Data Grid. Frustratingly, their were either bugs in the Data Grid or some props are so difficult to understand that I couldn’t tell the difference. The component has so much promise, but I think people will find attempts to go beyond default options too difficult.

Finally, an important consideration to remember with the Data Grid is that many props get set at the column level, while other props get set at the Data Grid level. For example, disabling sorting on a column requires a column prop, but setting a default sort on a column requires a Data Grid prop. We’ll see this in the code later on.

Full code with TypeScript for this Data Grid tutorial can be found in the Resources section.

YouTube video is here or watch below:

MUI Data Grid Sorting

Sort Docs

The Data Grid has sorting enabled by default. If you don’t want a particular column to sort, disable it by setting sortable: false on the column.

Here’s how the sort looks in the Data Grid header. Notice the arrow icon as a shortcut.

MUI Data Grid Sort
MUI Data Grid Sort

You can also set a default sort that takes effect on initial load of the component. Use the initialState prop at the Data Grid level. In this case I have set my field column to have an ascending sort on load.

initialState={{
  sorting: { sortModel: [{ field: "state", sort: "asc" }] }
}}

Custom sort algorithms can be set using the sortComparator prop at the column level. This would simply compare the two values in a unique way that fits your requirements.

MUI Data Grid Filtering

Filtering Docs

Filtering is also enabled by default. You can see it in the screenshot alongside sort functionality in the previous section.

Filtering can be disabled at the column level with filterable: false. It can be disabled for all columns by passing disableColumnFilter to the DataGrid.

I also attempted to set initialState.filter.filterModel on the Data Grid to set a default filter for the zip code column. I passed the required params of columnField, operatorValue, and value. However, the Data Grid threw an error:

MUI Data Grid No Filter Operator
MUI Data Grid No Filter Operator

The following are potential reasons for this issue:

  • I misunderstood the docs
  • This feature has a bug
  • I am attempting an invalid operator for a string field

Regardless, it was disappointing that after spending a reasonable amount of time digging into examples, I still couldn’t get the default filter to work.

MUI Data Grid Exporting

Export Docs

Exporting contents of the Data Grid can be enabled by passing a GridToolbar to the Data Grid:

components={{Toolbar: GridToolbar}}

This enables cool features like column hiding as well. However, this duplicates the filter option (it’s also available on each column).

MUI GridToolbar
MUI GridToolbar

I recommend passing a more precise value that contains only the Toolbar options you intend to use:

components={{ Toolbar: () => {
  return (<GridToolbarContainer sx={{justifyContent: 'flex-end'}}>
    <GridToolbarExport />
  </GridToolbarContainer>)} 
}}

Here I’ve passed a GridToolbarContainer that only has an export option. I also right-aligned the export.

If you don’t want a particular column exported, add disableExport: true to the column.

MUI Data Grid Pagination

Pagination Docs

Pagination was one of the simpler features to experiment with. There are two primary ways to configure pagination:

  • Auto-detect grid height and render few enough rows so a scrollbar isn’t needed.
  • Configure page size options that will render a set amount of rows regardless of grid height. This is the default.

Here’s an example of rendering based on grid height. This required setting autoPageSize={true} at the Data Grid level. Notice there is no “Rows per page” dropdown.

autoPageSize
autoPageSize

Here’s what the default pagination configuration looks like, except that I’ve configured the rows per page to have options of 20, 50, and 100.

MUI Data Grid rows per page
MUI Data Grid rows per page

Here’s more ideas for customizing the pagination component.

MUI Data Grid Cell Editing

Cell Editing Docs

Data Grid cells are not editable by default. However, editing can be enabled with editable: true at the column level.

Surprisingly, there are lots of configurations for editing. They primarily involve handling edit change events and controlling what the data looks like while editing.

I attempted to customize the rendered text during editing:

Editing MUI Data Grid cells
Editing MUI Data Grid cells

I used the following prop at the cell level:

renderEditCell: (val) => {console.log(val.value); return `Editing: ${val.value}` }

However, this didn’t take into account the changes to value and thus rendered the cell uneditable. I was attempting a simplified version of this example from the MUI docs. I found it complex to the point of being inaccessible. I only have access to the free Data Grid version, not the pro version, and perhaps if I had support from the MUI team then this feature would not be so challenging.

Material-UI Data Grid Bugs?

I’ve written almost 100 MUI articles on this site. I have encountered occasional head-scratchers and “is that a bug?” moments. However, I have found very specific problems with the Data Grid that I think are worth highlighting below. I still think the Data Grid is an excellent component, but be careful about customizing the "@mui/x-data-grid" version (or using it with TypeScript).

TypeScript challenges:

  • I tried to type my rows as type GridRowsProp from @mui/x-data-grid. However, this was set to a readonly array and thus lacked the push function. I ended up retyping the rows const.
  • I had to set //@ts-ignore on my GridToolbarContainer in order to use sx props with it. The sx prop obviously works, but MUI seems to be lacking proper typing for it on this component.
  • Pagination is enabled by default. In fact, it can’t be disabled if you are using TypeScript. The pagination prop typing only allows true or undefined as values. Maybe this is intentional, but then why include the prop?

Code challenges:

  • Data Grid height vs. minHeight. This was a difficult one…I initially set minHeight on the Data Grid instead of height. I couldn’t figure out why the rows wouldn’t render! It turns out that the Data Grid seems to not be unable to set height using minHeight. My guess is a fixed height is required for internal calculations such as autoPageSize.
  • Various challenges with getting customizations to work (renderEditCell, filterModel, and so on). Maybe this is MUI’s fault, maybe this is my fault.
Data Grid minHeight bug
Data Grid minHeight bug

Resources

Here’s a deep dive into customizing Data Grid styling and using renderCell.

Here’s how to add components to Data Grid columns.

I experimented with expandable rows in the free DataGrid, and it went better than expected!

Data Grid API Docs

import * as React from "react";
import { Paper, SxProps } from "@mui/material";
import { DataGrid, GridToolbar, GridRowsProp, GridColDef, GridToolbarContainer, GridToolbarExport } from "@mui/x-data-grid";
import { faker } from "@faker-js/faker";

const columns: GridColDef[] = [
  {
    field: "address",
    headerName: "Street/Appt Address",
    flex: 2,
    sortable: false,
    disableExport: true,
    filterable: false,
    editable: true
  },
  { field: "zip", headerName: "Zip Code", flex: 1, /*sortComparator: {}*/ },
  { field: "city", headerName: "City", flex: 1 },
  { field: "state", headerName: "State", flex: 1, editable: true, /* renderEditCell: (val) => {console.log(val.value); return `Editing: ${val.value}` } */},
];

//const addresses: GridRowsProp = [];
const addresses: {
    [key: string]: any;
}[] = [];

for (let i = 0; i < 200; i++) {
  addresses.push({
      id: i+1,
    address: `${faker.address.streetAddress()} ${faker.address.secondaryAddress()}`,
    zip: faker.address.zipCode(),
    city: faker.address.city(),
    state: faker.address.state(),
  });
}

const datagridSx: SxProps = {
  marginLeft: "auto",
  marginRight: "auto",
  marginTop: 4,
  width: "100%",
  //minHeight: 500,
  height: 500,
  borderRadius: 2,
};

export default function TutorialDataGrid() {
  //const [pageSize, setPageSize] = React.useState(20);

  return (
    <Paper sx={datagridSx}>
      <DataGrid
        rows={addresses}
        columns={columns}
        //@ts-ignore
        components={{ Toolbar: () => {return (<GridToolbarContainer sx={{justifyContent: 'flex-end'}}>
          <GridToolbarExport />
        </GridToolbarContainer>)} }}
        initialState={{
          sorting: { sortModel: [{ field: "state", sort: "asc" }] },
          // filter: {
          //   filterModel: {
          //     items: [
          //       {
          //         columnField: 'zip',
          //         operatorValue: '=',
          //         value: '78701'
          //       },
          //     ],
          //   },
          // }
        }}
        pagination={undefined}
        //autoPageSize={true}
        // pageSize={pageSize}
        // onPageSizeChange={(newPageSize) => setPageSize(newPageSize)}
        // rowsPerPageOptions={[20, 50, 100]}
      />
    </Paper>
  );
}
Share this post:

5 thoughts on “React MUI v5 Data Grid Tutorial: Sort, Filter, Export, Pagination and Cell Editing”

  1. Hi Jon,

    Nice post. I am unable to get the ‘sx’ working on the GridToolbarContainer. What version of x-data-grid did you use?

    Thanks!

    Reply
    • Hi Lynnae, I’m using @mui/x-data-grid 5.6.1. I had the same problem occur when I made the YouTube version of this post. It worked…until it didn’t. I finally had to use the style prop. I suspect a bug was introduced in a patch version of x-data-grid.

      Alternatively, you can add @ts-ignore in the line above the GridToolbarContainer.

      Reply
  2. Hi – Nice Post – wrt to the filtering options not working… I got it working as follow:

    const [filterModel, setFilterModel] = React.useState({
    items: [
    {
    columnField: ‘movementType’,
    operatorValue: ‘equals’, // This should be text check current available values in dropdown when setting filter manually.
    value: movementTypeToggle,
    },
    ],
    });

    Reply
  3. I am learning nextjs. Wanted to create datagrid with mui for crud management.
    This is ok with simulated data and client side process for limited data.

    How do you do filter with mysql database with sort filter search etc.

    You can update tutorial with mysql as data providers and server side filter / search etc.

    Reply

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.