The Ultimate Guide to Customizing Material-UI DataGrid: Height, Width, Alignment, Click Handlers, and More

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.

MUI DataGrid With Custom Header Styling, Row Height, Alignment, and More
MUI DataGrid With Custom Header Styling, Row Height, Alignment, and More

***UPDATE for MUI 5: Material-UI moved to a new styling API where styling is applied using the sx prop. I include code for both MUI v4 and v5 where necessary. Styling code is pretty similar for both versions.

Here’s a tutorial on sorting, filtering, exporting, and more for the Data Grid.

In this article I will construct a DataGrid with the custom features listed in the table of contents. Full code for v5 version can be found in the Resources section, as well as a link to a live Code Sandbox.

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

See the video version of this post on YouTube or below:

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

My MUI course on Udemy is now available!!! Build a full MUI app from beginning to end, learn every aspect of the sx prop, styled API, and the theme, and tackle the most challenging components! Do you want an active Q&A with me?!? Check here for coupons for my MUI course on Udemy.

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:

Material-UI DataGrid Document Object Model

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:

const useStyles = makeStyles((theme) =>
  createStyles({
    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"
        }
      }
    }
  })
);

//For MUI v5, remove the root wrapper and insert the styling code into sx prop

(Learn about the differences between makeStyles, useStyles, createStyles, and withStyles here.)

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”.

I also added expandable rows to the DataGrid, but I think it also risks interfering with internal DataGrid calculations.

MUI DataGrid Background Color and Alternating Row Color

Background color can be set in MUI’s DataGrid by targeting .root -> .MuiDataGrid-renderingZone -> .MuiDataGrid-row, similar to the below code. This sets the background color at the row level.

If you want to alternate row color, consider using the nth-child selector. I’ve used the 2n modifier on it so that every other row is styled, starting with the second row. If I passed 2n-1, it would style every other row starting with the first row.

If you need to target background color at the cell level, you can do so by styling a custom component and rendering with renderCell, discussed below.

//MUI v4
root: {
  "& .MuiDataGrid-renderingZone": {
    "& .MuiDataGrid-row": {
      "&:nth-child(2n)": { 
        backgroundColor: "rgba(235, 235, 235, .7)" 
      }
    }
  }
}

//MUI v5 (notice the class name difference)
"& .MuiDataGrid-virtualScrollerRenderZone": {
  "& .MuiDataGrid-row": {
    "&:nth-child(2n)": { backgroundColor: "rgba(235, 235, 235, .7)" }
  }
}

MUI DataGrid Header Style

In Material-UI version 5, the DataGrid header can be styled by using a nested selector that selects the MuiDataGrid-columnHeaders class. Using the CSS below, I set background color, text color, and font size in the MUI DataGrid header. This CSS is in the DataGrid’s sx prop.

//MUI v5
"& .MuiDataGrid-columnHeaders": {
  backgroundColor: "rgba(0,0,255,0.6)",
  color: "rgba(255,0,0,0.7)",
  fontSize: 16
}

The header can be styled in other ways. Header height can be set at the DataGrid level with the headerHeight prop. Individual column headers can be aligned using headerAlign.

Individual column headers can be styled by selecting .MuiDataGrid-columnHeader:nth-of-child. This will select a single column header or repeating pattern of headers for styling.

MUI 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 MUI DataGrid 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",
  headerAlign: "left"
}

Columns of type ‘number’ are right aligned by default. Specifying left in the Column object adjusts that. However, the alignment only adjusts the value cells, not the header. The header must be separately aligned by setting headerAlign: "left".

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.

MUI DataGrid 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:

Material-UI Column Box Model
Material-UI Column Box Model

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

MUI DataGrid Auto Column Width

If you want columns to automatically adjust their width to fill the DataGrid’s container, use a combination of minWidth and flex.

This provides a minimum structure to your column if you add more columns in the future. It also stretches all the columns that have a flex value, if there is room to stretch.

In the example below I swapped width for minWidth and flex in two columns.

{
  field: "age",
  headerName: "Age",
  type: "number",
  //width: 90,
  minWidth: 90,
  flex: 1
},
{
  field: "fullName",
  headerName: "Full name",
  description: "This column has a value getter and is not sortable.",
  sortable: false,
  minWidth: 160,
  flex: 2,
  //width: 160
}
Data Grid with auto column with
Data Grid with auto column with

MUI DataGrid 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

import * as React from "react";
import { DataGrid } from "@mui/x-data-grid";
import { Toolbar } from "@mui/material/Toolbar";

const datagridSx = {
  borderRadius: 2,
  "& .MuiDataGrid-main": { borderRadius: 2 },
  '& div[data-rowIndex][role="row"]:nth-of-type(5n-4)': {
    color: "blue",
    fontSize: 18,
    //risky
    minHeight: "60px !important",
    height: 60,
    "& div": {
      minHeight: "60px !important",
      height: 60,
      lineHeight: "59px !important"
    }
  },
  "& .MuiDataGrid-virtualScrollerRenderZone": {
    "& .MuiDataGrid-row": {
      "&:nth-child(2n)": { backgroundColor: "rgba(235, 235, 235, .7)" }
    }
  },
  "& .MuiDataGrid-columnHeaders": {
    backgroundColor: "rgba(0,0,255,0.6)",
    color: "rgba(255,0,0,0.7)",
    fontSize: 16
  }
};

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);
};

const columns = [
  {
    field: "id",
    headerName: "ID",
    width: 70
  },
  {
    field: "firstName",
    headerName: "First Name",
    width: 130,
    renderCell: (cellValues) => {
      return (
        <div
          style={{
            color: "blue",
            fontSize: 18,
            width: "100%",
            textAlign: "right"
          }}
        >
          {cellValues.value}
        </div>
      );
    }
  },
  { field: "lastName", headerName: "Last Name", width: 130 },
  {
    field: "age",
    headerName: "Age",
    headerAlign: "left",
    type: "number",
    //width: 90,
    minWidth: 90,
    flex: 1,
    align: "left"
  },
  {
    field: "fullName",
    headerName: "Full name",
    description: "This column has a value getter and is not sortable.",
    sortable: false,
    minWidth: 160,
    flex: 2,
    //width: 160,
    valueGetter: (params) => {
      return `${params.getValue(params.id, "firstName") || ""} ${
        params.getValue(params.id, "lastName") || ""
      }`;
    }
  }
];

const rows = [
  { id: 1, lastName: "Snow", firstName: "Jon", age: 35 },
  { id: 2, lastName: "Lannister", firstName: "Amy", age: 42 },
  {
    id: 3,
    lastName: "IGOTAREALLyLONGNAME!!!!!!!",
    firstName: "Jaime",
    age: 45
  },
  { id: 4, lastName: "Stark", firstName: "Arya", age: 16 },
  { id: 5, lastName: "Targaryen", firstName: "Daenerys", age: 12 },
  { id: 6, lastName: "Melisandre", firstName: "Jane", age: 15 },
  { id: 7, lastName: "Clifford", firstName: "Ferrara", age: 44 },
  { id: 8, lastName: "Frances", firstName: "Rossini", age: 36 },
  { id: 9, lastName: "Roxie", firstName: "Harvey", age: 65 }
];

export default function DataGridDemo() {
  return (
    <div style={{ height: 500, width: "100%" }}>
      <DataGrid
        //toolBar={<Toolbar sx={{ backgroundColor: "blue" }} />}
        headerHeight={60}
        rowHeight={120}
        sx={datagridSx}
        rows={rows}
        columns={columns}
        pageSize={5}
        checkboxSelection
        onCellClick={handleCellClick}
        onRowClick={handleRowClick}
      />
      <div style={{ margin: "40px", textAlign: "center" }}>
        <a
          target="_blank"
          href="https://smartdevpreneur.com/the-ultimate-guide-to-customizing-material-ui-datagrid/"
        >
          How do you customize the DataGrid styling?
        </a>
      </div>
    </div>
  );
}

Test your JavaScript knowledge with these 50 challenging JavaScript questions!

Check out this post if you need to render buttons, links, or other components in your DataGrid.

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 link (v4).

Code Sandbox link (v5).

Docs for DataGrid

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

Share this post:

6 thoughts on “The Ultimate Guide to Customizing Material-UI DataGrid: Height, Width, Alignment, Click Handlers, and More”

  1. 1. How to prevent default scroll of DataGrid, and show all table width on the page?
    2. If text is long in a cell, how to make auto with or height that will show all text in a cell, no … three dots on the end if text so long, or other alternatives?

    Reply
  2. How do you add a dropdown for each row which gets its options from an array and the selected item is bound to a value from the grid and also the dropdown has an onChange Event which passes said value ?

    Reply

Leave a Comment

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