cells
When creating tables in your application you'll probably want to customize how certain cells are rendered. By default, the table will render basic text cells, but you can easily override this behavior by providing custom cell types.
This is achieved through the Cell property on the column definition, which allows you to specify a custom cell
renderer for that column. In the example below, we customize the "Microchip" column to render an icon indicating whether
the cat has a microchip or not instead of just rendering "true" or "false" text.
const columns: Columns<Cat> = [
{
accessorKey: 'microchip',
Cell: ({ cell }: { cell: MRT_Cell<Cat> }) => (
<Icon
color={cell.getValue() ? 'var(--bfc-success)' : 'var(--bfc-alert)'}
icon={cell.getValue() ? faCircleCheck : faCircleX}
/>
),
header: 'Microchip',
},
]
The function you provide to the Cell receives lots of props that can be used to determine what you render with the
most important ones probably being cell and row.
Below is an example with a full type definition for the Cell property:
import type { MRT_Cell, MRT_Column } from 'material-react-table'
import type { MRT_Row, MRT_TableInstance } from 'material-react-table'
import type { ReactNode, RefObject } from 'react'
const columns: Columns<Cat> = [
{
accessorKey: 'name',
Cell: ({
cell,
column,
renderedCellValue,
row,
rowRef,
staticColumnIndex,
staticRowIndex,
table,
}: {
cell: MRT_Cell<Cat, string>
column: MRT_Column<Cat, string>
renderedCellValue: ReactNode
row: MRT_Row<Cat>
rowRef?: RefObject<HTMLTableRowElement | null>
staticColumnIndex?: number
staticRowIndex?: number
table: MRT_TableInstance<Cat>
}) => <div>Meow</div>,
header: 'name',
},
]
In most cases cell, row, and table will be sufficient to create custom cell renderers, but the other props are
available if you need them.
Built-in Cell Types
To make development easier several built-in cell types are provided out-of-the-box.
And we have plans to add a bunch more in the future! Such as dates (#15), badges (#1148), buttons (#776) and more!
These cell types are exported from the main package as separate components that you can import and use in your column definitions. The built-in cell types integrate seamlessly with features like sorting, filtering, highlighting etc.
Navigation
A common need when displaying tables is to have cells that can be clicked to navigate to other pages or routes in or outside your application. Several built-in cell types are provided to handle different navigation scenarios.
All these navigation cell types support styling and highlighting to match the rest of the table, and accept any props to the underlying link component, enabling you to customize them as needed.
The framework-specific link cell types (ReactRouterLinkCell and TSRLinkCell) obviously require that you have the
respective routing library installed and set up in your application.
LinkCell
Renders a simple anchor (<a>) element for navigation to external URLs, with style matching and highlighting support.
const columns: Columns<Cat> = [
{
accessorKey: 'name',
Cell: ({ cell, row }: { cell: MRT_Cell<Cat>; row: MRT_Row<Cat> }) => {
const href = `https://www.google.com/search?q=${row.getValue<string>('breed')}+cat`
return <LinkCell cell={cell} href={href} />
},
header: 'Name',
},
]
This example is from the Kitchen Sink table, where the cat's name is a link to a Google search for the cat's breed.
ReactRouterLinkCell
Renders a React Router <Link> element for navigation within a React Router application.
const columns: Columns<Cat> = [
{
accessorKey: 'name',
Cell: ({ cell, row }: { cell: MRT_Cell<Cat>; row: MRT_Row<Cat> }) => (
<ReactRouterLinkCell cell={cell} to={row.original.id.toString()} />
),
header: 'Name',
},
]
TSRLinkCell
Renders a TanStack Router <Link> element for navigation within a TanStack Router application.
const columns: Columns<Cat> = [
{
accessorKey: 'name',
Cell: ({ cell, row }: { cell: MRT_Cell<Cat>; row: MRT_Row<Cat> }) => (
<TSRLinkCell cell={cell} to={row.original.id.toString()} />
),
header: 'Name',
},
]
ArrayCell
Sometimes your data may not be as flat as you wish, and you might have arrays that need to be displayed in a single
cell. The ArrayCell component makes it easy to render arrays in table cells.
The first element of the array is always shown, and if there are more elements, a button with the count to expand the items.
import { arrayCellMultiSelectFilterFn, arrayCellSortingFn } from '@intility/gjallarbru'
const columns: Columns<Cat> = [
{
accessorKey: 'skills',
Cell: ({ cell, table }: { cell: MRT_Cell<Cat>; table: MRT_TableInstance<Cat> }) => (
<ArrayCell cell={cell} elements={cell.getValue<string[]>()} table={table} />
),
filterFn: arrayCellMultiSelectFilterFn,
filterVariant: 'multi-select',
header: 'Skills',
sortingFn: arrayCellSortingFn,
},
]
In the example above, a custom sort and filter function is also used to enable sorting and filtering on the array values, you can of course provide your own custom implementations if needed, but these built-in functions should cover most use cases.
In the example below, no filterVariant is specified, so the default text filter is used instead, for array cells you
can then use the built-in arrayCellTextFilterFn filter function to enable text filtering on the array values.
import { arrayCellSortingFn } from '@intility/gjallarbru'
const columns: Columns<Cat> = [
{
accessorKey: 'skills',
Cell: ({ cell, table }: { cell: MRT_Cell<Cat>; table: MRT_TableInstance<Cat> }) => (
<ArrayCell cell={cell} elements={cell.getValue<string[]>()} table={table} />
),
filterFn: arrayCellTextFilterFn,
header: 'Skills',
sortingFn: arrayCellSortingFn,
},
]
Helpers
When you use your own custom Cell: renderers, you loose some of the built-in functionality provided, such as text
highlighting and truncation. To help with this, we provide some helper components that you can use within your custom
cell renderers to easily add these features back in.
CellText
This component wraps the CellHighlight component and provides text truncation functionality through the
Bifrost Ellipsis component.
You can pass it the cell prop, and it will automatically render the cell value with highlighting and truncation.
const columns: Columns<Cat> = [
{
accessorKey: 'name',
Cell: ({ cell }: { cell: MRT_Cell<Cat> }) => (
<>
<CatPicture />
<CellText cell={cell} />
</>
),
header: 'Name',
},
]
You can also pass it children to customize the rendered value while still getting highlighting and truncation.
const columns: Columns<Cat> = [
{
accessorKey: 'name',
Cell: ({ cell }: { cell: MRT_Cell<Cat> }) => (
<>
<CatPicture name={cell.getValue<string>()} />
<CellText cell={cell}>Macavity, Macavity, there's no one like Macavity</CellText>
</>
),
header: 'Name',
},
]
CellHighlight
If you don't want truncation, you can use the CellHighlight component to just get text highlighting for your custom
cell renderers. It works exactly like CellText but without the truncation.
const columns: Columns<Cat> = [
{
accessorKey: 'name',
Cell: ({ cell }: { cell: MRT_Cell<Cat> }) => (
<>
<CatPicture />
<CellHighlight cell={cell} />
</>
),
header: 'Name',
},
]
Header
You can also customize how headers are rendered using the Header property on the column definition. It works similarly
to the Cell property, allowing you to provide a custom header renderer for that column.
Here we also provide a helper component HeaderCell that you can use to get consistent styling and behavior for your
custom headers. In the example below we customize the header for the "Name" column to render the text in red, with the
HeaderCell component wrapping our custom content, while the "Breed" column header is customized without the helper
component.
Because the Header override in the "Breed" column does not use the HeaderCell component, it loses a lot of features
like column resizing, sorting, and column reordering support.
We generally recommend not to override the Header property unless you really need to, and if you do, use the
HeaderCell component to ensure consistent behavior and styling.
const columns: Columns<Cat> = [
{
accessorKey: 'name',
Header: ({ header, table }: { header: MRT_Header<Cat>; table: MRT_TableInstance<Cat> }) => (
<HeaderCell header={header} table={table}>
<div style={{ color: 'red' }}>Name</div>
</HeaderCell>
),
header: 'Name',
},
{
accessorKey: 'breed',
Header: ({ column }: { column: MRT_Column<Cat> }) => {
return <div style={{ color: 'hotpink' }}>Breed</div>
},
header: 'Breed',
},
]