The Ultimate Guide to Customizing Material-UI DataGrid

The Material-UI DataGrid component is designed for interacting with large data sets. However, it can be tricky to get the layout exactly like you want.

What We’ll Build

In this article I will construct a DataGrid with the following features (plus a Resources section):

These things may not sound complicated, but custom styling individual rows or cells can take significant CSS skills.

Unique row and column styling

Code Sandbox for this article is in the Resources section and is based on the fork of the MUI docs example.

Row Height

Setting row height for all rows is simple. Setting row height for individual rows is challenging in the DataGrid due to how it is virtualized.

<DataGrid
  rowHeight={120}
  className={classes.root}
  rows={rows}
  columns={columns}
  pageSize={5}
  checkboxSelection
  onCellClick={handleCellClick}
  onRowClick={handleRowClick}
/>

The above code is the React JSX for our DataGrid example. rowHeight={120} sets row height for all rows in the DataGrid.

Here’s why the DataGrid needs to know row height before any styling or rendering occurs:

This is a screenshot of the DOM structure showing alll the layers of container nesting in the data grid. The bottom element visible in the DOM is the first row. Above it are six layers of nesting, all there simply to aid in virtualization calculations and scrolling.

However, if you need to set row height for an individual row, consider the following:

root: {
  '& div[data-rowIndex][role="row"]:nth-of-type(5n-4)': {
    color: "blue",
    fontSize: 18,
    //risky sizing code starts here
    minHeight: "60px !important",
    height: 60,
    "& div": {
      minHeight: "60px !important",
      height: 60,
      lineHeight: "59px !important"
    }
  },
  "& .MuiDataGrid-renderingZone": {
    "& .MuiDataGrid-row": {
      "&:nth-child(2n)": { backgroundColor: "rgba(235, 235, 235, .7)" }
    }
  }
}

This is the first time I’ve ever had to use !important to accomplish a styling goal in Material-UI, and it was required here because the height for each row is set inline by MUI.

Two notes of caution here: First, adjusting the size of a single row won’t change the calculations already set in the inner workings of the data grid. Therefore, you will wind up with things like too much (or too little) whitespace below the bottom visible row. Second, this works to a degree for shrinking a row. For expanding a row’s height, it will push the bottom row out of view, and really shouldn’t be tried.

Ultimately, I don’t recommend trying to custom size a single row. It will be difficult and may have unexpected results.

As info, the default row height is 52px. It’s locked in with minHeight, maxHeight, and lineHeight, which seems to me that Material-UI is saying “Don’t mess with this”.

DataGrid Height

The data grid works nicely inside a container with a fixed height, such as a div or Material-UI Container. When it is rendered inside of the container, then the component will expand to fill the container’s height. If the container is not tall enough to contain the data grid’s height, the data grid will automatically render with a scrollbar.

If you do decide to set a height and not use an outer container, set the height through inline styling or a class. There is no height prop on the data grid itself.

If you attempt to set an individual row height as discussed in the previous section, then setting autoHeight={true} instead of a fixed height may help some to mitigate faulty row and grid calculations.

Aligning Cell Contents with Align and renderCell

Aligning text inside of DataGrid cells is straightforward. Here’s an example:

{
  field: "age",
  headerName: "Age",
  type: "number",
  width: 90,
  align: "left"
}

Columns of type ‘number’ are right aligned by default. Specifying left in the Column object adjusts that.

The Column API is powerful and being familiar with it’s props is important for use of DataGrids, Tables, and Grids in Material-UI.

Another option is the use the renderCell Column prop:

{
  field: "firstName",
  headerName: "First name",
  width: 130,
  renderCell: (cellValues) => {
    return (
      <div
        style={{
          color: "blue",
          fontSize: 18,
          width: "100%",
          textAlign: "right"
        }}
      >
      {cellValues.value}
      </div>
    );
  }
}

I had to set width: "100%" to get the div to take up all available space in the cell. Without that, visually it appeared that the textAlign: “right” wasn’t applied (even though it was). Additionally, I set color and fontSize just for visual interest.

Column Width

Column width is simply set with the width property in the column API. The “age” column above was set to 90px simply with width: 90.

By default, this includes 16px of padding on the left and right:

This leaves the actual cell content at width – 32, in this case about 58px.

Cell Click Vs Row Click

Event propagation in JavaScript starts with the most granular component and works its way up. In the case of our data grid, that means we can handle clicks at the cell or row depending on what was clicked.

For the example we’re building, I have a simple cell click handler and row click handler:

const handleCellClick = (param, event) => {
  console.log(param);
  console.log(event);
  if (param.colIndex === 2) {
    event.stopPropagation();
  }
};

const handleRowClick = (param, event) => {
  console.log("Row:");
  console.log(param);
  console.log(event);
};

I’ve specified that if a cell in the column with index of 2 is clicked, don’t let that bubble up to the row click handler. Other cell clicks are allowed to bubble up.

An example of when this might be desired is if column 2 cells are informational and we don’t want row actions to fire when column 2 cells are clicked.

There are many other handlers in the DataGrid API. A few interesting ones are onColumnHeaderDoubleClick, onColumnOrderChange, and onRowDoubleClick.

Material-UI Grid Vs DataGrid?

The Grid and the DataGrid are two significantly different components. The Grid component is usually focused on layout of components, not large quantities of data. For further reading on the React Material-UI Grid, see the following posts:

An overview of the Grid component.

Aligning items in the Grid.

Setting item height in the Grid.

Resources

Test your JavaScript knowledge with these 50 challenging JavaScript questions!

Consider using the MUI Skeleton as a loading indicator while your DataGrid is loading. It has a great look and feel that improves the user’s perception of page load time.

Code Sandbox:

Docs for DataGrid

Docs for understanding Column API (critical for being able to fully use DataGrid).

Share this post:

Leave a Comment

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