Note: This guide is about setting up column definitions for your table and NOT about the actual
column
objects that are generated within the table instance.
Column defs are the single most important part of building a table. They are responsible for:
The following "types" of column defs aren't actually TypeScript types, but more so a way to talk about and describe overall categories of column defs:
Accessor Columns
Display Columns
Grouping Columns
While column defs are just plain objects at the end of the day, a createColumnHelper
function is exposed from the table core which, when called with a row type, returns a utility for creating different column definition types with the highest type-safety possible.
Here's an example of creating and using a column helper:
// Define your row shapetype Person = { firstName: string lastName: string age: number visits: number status: string progress: number}
const columnHelper = createColumnHelper<Person>()
// Make some columns!const defaultColumns = [ // Display Column columnHelper.display({ id: 'actions', cell: props => <RowActions row={props.row} />, }), // Grouping Column columnHelper.group({ header: 'Name', footer: props => props.column.id, columns: [ // Accessor Column columnHelper.accessor('firstName', { cell: info => info.getValue(), footer: props => props.column.id, }), // Accessor Column columnHelper.accessor(row => row.lastName, { id: 'lastName', cell: info => info.getValue(), header: () => <span>Last Name</span>, footer: props => props.column.id, }), ], }), // Grouping Column columnHelper.group({ header: 'Info', footer: props => props.column.id, columns: [ // Accessor Column columnHelper.accessor('age', { header: () => 'Age', footer: props => props.column.id, }), // Grouping Column columnHelper.group({ header: 'More Info', columns: [ // Accessor Column columnHelper.accessor('visits', { header: () => <span>Visits</span>, footer: props => props.column.id, }), // Accessor Column columnHelper.accessor('status', { header: 'Status', footer: props => props.column.id, }), // Accessor Column columnHelper.accessor('progress', { header: 'Profile Progress', footer: props => props.column.id, }), ], }), ], }),]
Data columns are unique in that they must be configured to extract primitive values for each item in your data
array.
There are 3 ways to do this:
objects
, use an object-key that corresponds to the value you want to extract.arrays
, use an array index that corresponds to the value you want to extract.If each of your items is an object with the following shape:
type Person = { firstName: string lastName: string age: number visits: number status: string progress: number}
You could extract the firstName
value like so:
columnHelper.accessor('firstName')
// OR
{ accessorKey: 'firstName',}
If each of your items is an object with the following shape:
type Person = { name: { first: string last: string } info: { age: number visits: number }}
You could extract the first
value like so:
columnHelper.accessor('name.first', { id: 'firstName',})
// OR
{ accessorKey: 'name.first', id: 'firstName',}
If each of your items is an array with the following shape:
type Sales = [Date, number]
You could extract the number
value like so:
columnHelper.accessor(1)
// OR
{ accessorKey: 1,}
If each of your items is an object with the following shape:
type Person = { firstName: string lastName: string age: number visits: number status: string progress: number}
You could extract a computed full-name value like so:
columnHelper.accessor(row => `${row.firstName} ${row.lastName}`, { id: 'fullName',})
// OR
{ id: 'fullName', accessorFn: row => `${row.firstName} ${row.lastName}`,}
🧠Remember, the accessed value is what is used to sort, filter, etc. so you'll want to make sure your accessor function returns a primitive value that can be manipulated in a meaningful way. If you return a non-primitive value like an object or array, you will need the appropriate filter/sort/grouping functions to manipulate them, or even supply your own! 😬
Columns are uniquely identified with 3 strategies:
.
) in an object key will be replaced by underscores (_
).id
property will be used to uniquely identify the column ORstring
header is supplied, that header string will be used to uniquely identify the column🧠An easy way to remember: If you define a column with an accessor function, either provide a string header or provide a unique
id
property.
By default, columns cells will display their data model value as a string. You can override this behavior by providing custom rendering implementations. Each implementation is provided relevant information about the cell, header or footer and returns something your framework adapter can render eg. JSX/Components/strings/etc. This will depend on which adapter you are using.
There are a couple of formatters available to you:
cell
: Used for formatting cells.aggregatedCell
: Used for formatting cells when aggregated.header
: Used for formatting headers.footer
: Used for formatting footers.You can provide a custom cell formatter by passing a function to the cell
property and using the props.getValue()
function to access your cell's value:
columnHelper.accessor('firstName', { cell: props => <span>{props.getValue().toUpperCase()}</span>,})
Cell formatters are also provided the row
and table
objects, allowing you to customize the cell formatting beyond just the cell value. The example below provides firstName
as the accessor, but also displays a prefixed user ID located on the original row object:
columnHelper.accessor('firstName', { cell: props => ( <span>{`${props.row.original.id} - ${props.getValue()}`}</span> ),})
For more info on aggregated cells, see grouping.
Headers and footers do not have access to row data, but still use the same concepts for displaying custom content.
Your weekly dose of JavaScript news. Delivered every Monday to over 100,000 devs, for free.