40

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.

Olivier Tassinari
  • 8,238
  • 4
  • 23
  • 23
Ni Tai
  • 499
  • 1
  • 7
  • 13
  • 1
    Can you add some code that can be used to recreate the issue? You can also try to produce a runnable functioning program that presents the issue using http://codesandbox.io – 95faf8e76605e973 Oct 13 '20 at 08:16
  • https://codesandbox.io/s/nostalgic-feistel-cg9wq?file=/src/App.js – Ni Tai Oct 13 '20 at 08:25

5 Answers5

67

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

Olivier Tassinari
  • 8,238
  • 4
  • 23
  • 23
NearHuscarl
  • 66,950
  • 18
  • 261
  • 230
  • not sure how to use it can u do it in this code? https://codesandbox.io/s/nostalgic-feistel-cg9wq?file=/src/App.js – Ni Tai Oct 13 '20 at 08:28
  • Just copy the `colDef` with the custom `renderCell` property in it. You can see in your demo [here](https://codesandbox.io/s/64331095cant-add-a-button-to-every-row-in-material-ui-table64331367noredirect1comment11375713464331367-juizs?file=/src/App.js) @NiTai – NearHuscarl Oct 13 '20 at 08:32
  • When I add a method to the button which updates the state I get maxiumum depth exceeded error. Does anyone else experience this? – Re-Angelo Apr 24 '21 at 22:35
  • `Module '"@material-ui/data-grid"' has no exported member 'ColDef'.` – fuat Apr 26 '21 at 17:30
  • @fuat if you're using newer package, replace `ColDef` with `GridColDef`. See [this](https://github.com/mui-org/material-ui-x/releases/tag/v4.0.0-alpha.21) changelog (PR #1069) – NearHuscarl Apr 26 '21 at 17:39
  • I replaced it but now: `Type '(params: GridCellParams) => void' is not assignable to type '(params: GridCellParams) => ReactElement>'.` – fuat Apr 26 '21 at 17:45
  • @fuat I've updated the codesandbox's `@material-ui/data-grid` to the latest version and fixed the type issue in older version. About your particular problem, it seems like your `renderCell` doesn't return anything. It should return a react component like `` for example. Please fork my codesandbox and put your link here if you still have any problem – NearHuscarl Apr 26 '21 at 17:52
  • Thank you for your effort but there is a little issue due to Typescript: `No index signature with a parameter of type 'string' was found on type '{}'. TS7053` this is about `thisRow` variable. – fuat Apr 26 '21 at 18:04
  • @fuat Replace `const thisRow` with `const thisRow: Record`. See my updated codesandbox – NearHuscarl Apr 26 '21 at 18:08
  • You are awesome, thanks a lot, I can not find the types, – fuat Apr 26 '21 at 18:10
  • So in such a case how can set the row value in the state? – fuat Apr 26 '21 at 19:50
  • @fuat Sorry I'm not sure what you mean. `GridCellValue` and all other public types can be found in `"@material-ui/data-grid"` module. – NearHuscarl Apr 26 '21 at 19:53
  • I want to open a dialog when clicking the button – fuat Apr 26 '21 at 19:57
  • 1
    @fuat Can you open a new question with more detail about what you want. This chat is getting rather long. – NearHuscarl Apr 26 '21 at 20:00
  • This is a typescript code. Can you please include the code for javascript or jsx file – Guit Adharsh Nov 30 '22 at 05:42
41

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>
        )
    }
Zack Amin
  • 514
  • 4
  • 12
11

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>
      );
  },
}
Olivier Tassinari
  • 8,238
  • 4
  • 23
  • 23
Joseph
  • 1,458
  • 15
  • 20
8

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)

LuvForAirplanes
  • 761
  • 8
  • 23
0

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.

zoltankundi
  • 181
  • 1
  • 1
  • 11