How to add a button to every row in MUI X DataGrid

87.1k views Asked by At

I can't add a button into every row of MUI X DataGrid. I have an MUI X DataGrid which I render like this:

<DataGrid rows={rows} columns={columns} pageSize={5} checkboxSelection />

I have added into the columns variable 'actions' column where the button should be rows are just a data object I get from the props. How can I add a button to every row (for editing the row)? I have tried mapping the data array but it is not possible to add a JSX button into every object of data.

5

There are 5 answers

15
NearHuscarl On BEST ANSWER

You can add your custom component by overriding GridColDef.renderCell method and return whatever element you want.

The example below displays an action column that renders a single button in each row. When clicking the button, it alerts the current row data in JSON string:

const columns: GridColDef[] = [
  { field: "id", headerName: "ID", width: 70 },
  {
    field: "action",
    headerName: "Action",
    sortable: false,
    renderCell: (params) => {
      const onClick = (e) => {
        e.stopPropagation(); // don't select this row after clicking

        const api: GridApi = params.api;
        const thisRow: Record<string, GridCellValue> = {};

        api
          .getAllColumns()
          .filter((c) => c.field !== "__check__" && !!c)
          .forEach(
            (c) => (thisRow[c.field] = params.getValue(params.id, c.field))
          );

        return alert(JSON.stringify(thisRow, null, 4));
      };

      return <Button onClick={onClick}>Click</Button>;
    }
  },
];

Edit 64331095/cant-add-a-button-to-every-row-in-material-ui-table

1
Zack Amin On

Just came across this.

What you need to do is include a renderCell method in your columns array.

 const columns = [
    {
        field: 'col1',
        headerName: 'Name 1',
        width: 150,
        disableClickEventBubbling: true,
    },
    {
        field: 'col2',
        headerName: 'Name 2',
        width: 300,
        disableClickEventBubbling: true,
    },
    {
        field: 'col3',
        headerName: 'Name 3',
        width: 300,
        disableClickEventBubbling: true,
    },
    {
        field: 'col4',
        headerName: 'Name 4',
        width: 100,
        disableClickEventBubbling: true,
    },
    {
        field: 'col5',
        headerName: 'Name 5',
        width: 150,
        ***renderCell: renderSummaryDownloadButton,***
        disableClickEventBubbling: true,
    },
    {
        field: 'col6',
        headerName: 'Name 6',
        width: 150,
        ***renderCell: renderDetailsButton,***
        disableClickEventBubbling: true,
    },
]

In the above I am rendering a Button inside columns 5 and 6 which will appear on every populated row.

Above that you can have a function which creates and returns a Button from Material-ui.

 const renderDetailsButton = (params) => {
        return (
            <strong>
                <Button
                    variant="contained"
                    color="primary"
                    size="small"
                    style={{ marginLeft: 16 }}
                    onClick={() => {
                        parseName(params.row.col6)
                    }}
                >
                    More Info
                </Button>
            </strong>
        )
    }
2
zoltankundi On

The currently top voted answer is outdated as of v5, because the new GridRowParams interface contains the actual row as a parameter, making the manual filtering from the GridApi unnecessary and unpractical.

Using this with renderCell can be as simple as

const columns: GridColDef[] = [
  { field: "id", headerName: "ID", width: 70 },
  {
    field: "action",
    headerName: "Action",
    sortable: false,
    renderCell: ({ row }: Partial<GridRowParams>) =>
      <Button onClick={() => yourActionFunction(row)}>
        Action
      </Button>,
  },
]

in TypeScript or

const columns = [
  { field: "id", headerName: "ID", width: 70 },
  {
    field: "action",
    headerName: "Action",
    sortable: false,
    renderCell: ({ row }) =>
      <Button onClick={() => yourActionFunction(row)}>
        Action
      </Button>,
  },
]

in plain JavaScript.

5
LuvForAirplanes On

While @NearHuscarl's response answers the question perfectly, I'd like to post a TypeScript example:

  const onClick = () => {
    const api: GridApi = params.api;
    const fields = api
      .getAllColumns()
      .map((c) => c.field)
      .filter((c) => c !== "__check__" && !!c);
    const thisRow: any = {};

    fields.forEach((f) => {
      thisRow[f] = params.getValue(params.id, f);
    });

    return alert(JSON.stringify(thisRow, null, 4));
  };

  return <Button onClick={onClick}>Click</Button>;

Also note, I changed the getValue call. (included the row id)

0
Joseph On

According to MUI X v5 params.getValue method is deprecated and will be removed in the next major version, Instead, you can access the current row data from params.row.

{
  field: 'action',
  headerName: 'Action',
  width: 180,
  sortable: false,
  disableClickEventBubbling: true,
  
  renderCell: (params) => {
      const onClick = (e) => {
        const currentRow = params.row;
        return alert(JSON.stringify(currentRow, null, 4));
      };
      
      return (
        <Stack direction="row" spacing={2}>
          <Button variant="outlined" color="warning" size="small" onClick={onClick}>Edit</Button>
          <Button variant="outlined" color="error" size="small" onClick={onClick}>Delete</Button>
        </Stack>
      );
  },
}