React table v8 - how to render custom cell content?
Asked Answered
P

3

8

I'm using @tanstack/react-table v8, and I want to have some icons and buttons in one of my table row cells. Looking at the docs I can use a display column for this:

Display columns do not have a data model which means they cannot be sorted, filtered, etc, but they can be used to display arbitrary content in the table, eg. a row actions button, checkbox, expander, etc.

The docs also mention this about custom rendering of cell content: By default, columns cells will display their data model value as a string. You can override this behavior by providing custom rendering implementations. ... You can provide a custom cell formatter by passing a function to the cell property ...

The docs show this example for custom rendering of a cell:

columnHelper.accessor('firstName', {
  cell: props => <span>{props.getValue().toUpperCase()}</span>,
})

So, I have defined a display column using ColumnHelper:

columnHelper.display({
  id: "actions",
  cell: (props) => (
    <div className="w-10 h-10 bg-red">
      <span>actions?</span>
    </div>
  ),
}),

How do I access this render function when creating the table? I'm creating the table body as follows (the table variable is returned by the useReactTable hook):

<tbody>
  {table.getRowModel().rows.map((row, index) => (
    <tr className={classNames(index % 2 !== 0 && "bg-tableRowGray")}>
      {row.getAllCells().map((cell) => (
        <td>{cell.getValue()}</td>
      ))}
    </tr>
  ))}
</tbody>

cell.getValue() and cell.renderValue() do not call the custom render function and I don't see any other render functions on the cell object. Am I just overlooking something really simple here?

Pole answered 29/9, 2022 at 8:12 Comment(0)
P
5

Turns out I was overlooking something simple. @tanstack/react-table exports a flexRender function which is used to render the cell, e.g.

import {flexRender} from "@tanstack/react-table";

...

<tbody>
  {table.getRowModel().rows.map((row, index) => (
    <tr className={classNames(index % 2 !== 0 && "bg-tableRowGray")}>
      {row.getAllCells().map((cell) => (<td>{flexRender(cell.column.columnDef.cell, cell.getContext())}</td>))}
    </tr>
  ))}
</tbody>

Pole answered 30/9, 2022 at 8:15 Comment(0)
T
3

I had the same issue while trying to render custom components for each cell and this is the solution that I came up with:

    const cols = [
          {
            header: "Actions",
            cell: (row) => {
              return (
                <button 
                  // onClick={a function based on the cell value}
                >
                  {row.getValue() as ReactNode}
                </button>
              );
            },
            accessorKey: "actions",
          },
        ],

As you can see the columns array that is passed gets a cell prop. Inside it, you can pass a function that return your desired JSX component.

Tommy answered 6/6, 2023 at 15:17 Comment(1)
Any idea how to implement the same thing in Vue (i.e. without JSX)?Composed
D
1

In order to simplify it without affecting other columns, you can get the row data inside the column definition with row.original.yourfieldhere

{
  id: "actions",
  cell: ({row}) => (
    <div className="w-10 h-10 bg-red">
      <span>{row.original.actions}</span>
    </div>
  ),
}
Derril answered 21/5, 2024 at 14:9 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.