The Essential Guide to MUI Table onClick: Row, Cell, & More

MUI Table clicks can happen at a variety of component levels. For example, we can have a click handler on a TableCell and a TableRow, and both of them can trigger from the same click.

In this post we’ll look at click handlers on the following MUI components:

  • TableCell
  • TableRow
  • TableHead
  • TableContainer

Furthermore, we have a significant amount of data in the click event that can be used in the handler. We’ll explore the values available on the event object and how they can be used. I will include full TypeScript support.

Material-UI Table onClick With TypeScript

If you are using TypeScript, all the Table components can be typed the same generic way if desired: (e: React.MouseEvent<HTMLElement>) => void.

MUI Table Cell Click Handler With TypeScript
MUI Table Cell Click Handler With TypeScript

Alternatively, each element’s click handler can take a type specific to what kind of element was clicked. Here’s another TableCell click handler: (e: React.MouseEventHandler<HTMLTableCellElement>) => void.

MUI Table onClick Event Values

In the example below I open an alert on click of the TableHead component.

Take a look at the values present on the event object. Values like cellIndex and innerHTML are particularly useful. There is lots of useful data in the event object for whatever your objective is.

Values available in the MUI tablecell click event
Values available in the table cell click event

In my example, I added a click handler at both the TableHead level and the TableCell level (children inside the TableBody). The JSX is abbreviated below.

export default function StylishTable() {
  const [snackbarOpen, setSnackbarOpen] = React.useState(false);
  const [infoText, setInfoText] = React.useState("a data");

  const tableCellClickHandler = 
    (e: React.MouseEvent<HTMLElement>) => 
  {
    console.log((e.target as Element).innerHTML);
  };

  const tableHeaderClickHandler = 
    (e: React.MouseEvent<HTMLElement>) => 
  {
    setSnackbarOpen(true);
    if (((e.target as unknown) as Cell).cellIndex) {
      setInfoText("data");
    } else {
      setInfoText("title");
    }
  };

//JSX snippets
<TableHead onClick={tableHeaderClickHandler} />

//These are cells in the TableBody component
<TableCell onClick={tableCellClickHandler} />
<TableCell onClick={tableCellClickHandler} />
<TableCell onClick={tableCellClickHandler} />
<TableCell onClick={tableCellClickHandler} />

The click handler in the TableHeader could have just as easily been placed on the TableRow that contained all the cells in the header.

The result of the header click handler is that an alert is opened inside a snackbar component. If the cell clicked has an index of zero, then the text in the snackbar displays “This is a title cell”. If the index is greater than zero, then the text displays “This is a data cell”.

The TypeScript typing on the header click handler was challenging. Event targets can be difficult to ‘type’ properly, and the cellIndex value mysteriously gets added to the event target in this click event. Because of this, I simply casted the event target to ‘unknown’ and then casted it as having a cellIndex value. Even if I typed as the more specific HTMLTableSectionElement the event still did not have cellIndex.

The click handler on the TableCell is simpler. It can be cast as an Element and then element values such as innerHTML are available. Read this helpful post for more detail on the TypeScript error that occurs if you don’t cast the event target value.

MUI TableCell, TableRow, TableHead, and TableContainer onClick Example

I added a click listener on a cell inside the row inside the header, all of which is inside the TableContainer. The click on the cell bubbled up the DOM as expected and and each handler logged a message sequentially:

MUI Table Click Bubbling
MUI Table Click Bubbling

Full Code and Related Links

I removed the styling from the code below. Here’s how to set table border, background color, font size, and other styling.

More useful MUI table resources:

import React from "react";
import Alert from "@mui/material/Alert";
import Snackbar from "@mui/material/Snackbar";
import Table from "@mui/material/Table";
import TableBody from "@mui/material/TableBody";
import TableCell from "@mui/material/TableCell";
import TableContainer from "@mui/material/TableContainer";
import TableHead from "@mui/material/TableHead";
import TableRow from "@mui/material/TableRow";
import Paper from "@mui/material/Paper";

interface Cell {
  cellIndex: number;
}

const tableStyling = {
  padding: "0px 0px"
};

function createData(name: string, calories: number, fat: number, carbs: number, protein: number) {
  return { name, calories, fat, carbs, protein };
}

const rows = [
  createData("Donut", 159, 6.0, 24, 4.0),
  createData("Hot Dog", 237, 9.0, 37, 4.3),
  createData("Pizza", 262, 16.0, 24, 6.0),
  createData("Pie", 305, 3.7, 67, 4.3),
  createData("Sandwich", 356, 16.0, 49, 3.9)
];

export default function ClickTable() {
  const [snackbarOpen, setSnackbarOpen] = React.useState(false);
  const [infoText, setInfoText] = React.useState("a data");

  const tableCellClickHandler = (e: React.MouseEvent<HTMLElement>) => {
    console.log((e.target as Element).innerHTML);
  };

  const tableHeaderClickHandler = (e: React.MouseEvent<HTMLElement>) => {
    console.log("Detected Header Click");
    setSnackbarOpen(true);
    if (((e.target as unknown) as Cell).cellIndex) {
      setInfoText("data");
    } else {
      setInfoText("title");
    }
  };

  const handleAlertClose = () => {
    setSnackbarOpen(false);
  };

  return (
    <div>
      <TableContainer
        onClick={() => {
          console.log("Detected Table Container Click");
        }}
        component={Paper}
      >
        <Table sx={{ tableLayout: "auto" }}>
          <TableHead onClick={tableHeaderClickHandler}>
            <TableRow
              onClick={() => {
                console.log("Detected Row Click");
              }}
            >
              <TableCell
                onClick={() => {
                  console.log("Detected Cell Click");
                }}
              >
                Food
              </TableCell>
              <TableCell sx={{ ...tableStyling, width: 100 }} align="right">
                Calories
              </TableCell>
              <TableCell sx={{ ...tableStyling, width: 100 }} align="right">
                Fat
              </TableCell>
              <TableCell sx={{ ...tableStyling, width: 100 }} align="right">
                Carbs
              </TableCell>
              <TableCell sx={{ ...tableStyling, width: "25%" }} align="right">
                Protein
              </TableCell>
            </TableRow>
          </TableHead>
          <TableBody>
            {rows.map((row) => (
              <TableRow key={row.name}>
                <TableCell
                >
                  {row.name}
                </TableCell>
                <TableCell
                  onClick={tableCellClickHandler}
                >
                  {row.calories}
                </TableCell>
                <TableCell
                  onClick={tableCellClickHandler}
                >
                  {row.fat}
                </TableCell>
                <TableCell
                  onClick={tableCellClickHandler}
                >
                  {row.carbs}
                </TableCell>
                <TableCell
                  onClick={tableCellClickHandler}
                >
                  {row.protein}
                </TableCell>
              </TableRow>
            ))}
          </TableBody>
        </Table>
      </TableContainer>
      <Snackbar
        open={snackbarOpen}
        autoHideDuration={3000}
        onClose={handleAlertClose}
      >
        <Alert severity="info" sx={{ width: "100%" }}>
          This is a {infoText} column.
        </Alert>
      </Snackbar>
    </div>
  );
}

MUI Table Component API

Share this post:

Leave a Comment

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