Skip to main content
K
Last modified: 4/Oct/2024

Table

Tables represent a set of data arranged in rows and columns.

#Usage

Simple table

import { Table } from '@kinsta/stratus' import type { TableColumnDef, } from '@kinsta/stratus' type Person = { id: number firstName: string lastName: string } export const TableExample = (): JSX.Element => { const data: Person[] = [ { id: 1, firstName: 'tanner', lastName: 'linsley', }, { id: 2, firstName: 'tandy', lastName: 'miller', }, ] const columns: TableColumnDef<Person>[] = [ { id: 'firstName', header: 'First name', accessorKey: 'firstName', }, { id: 'lastName', header: 'Last name', accessorKey: 'lastName', }, ] return ( <Table<Person> columns={columns} data={data} /> ) }

#Table Props

#data
Required
TData[]
Data to display in the table
#columns
Required
TableColumnDef<TData>[]
The displayed columns for the table columns
#onRowClick
(row: TData) => void
Table row onClick options
#expandOnRowClick
boolean
Expands selected row on row click if enableExpanding is true. Defaults to
true
#isExpandedByDefault
boolean
Decides if expandable rows are expanded by default. Defaults to false.
false
#subRowCellCustomStyles
SerializedStyles
Custom styles for the sub rows's cells
#isExpandableRowDense
boolean
Decides if expanded child rows are dense
false
#enableSubRowSelection
boolean
Decides if sub row selection is enabled for multiselect
false
#multiselect
MultiSelect<TData>
Multiselect checkbox options
#isControlled
boolean
Set the table to controlled mode
#isSortingEnabled
boolean
Decides the sorting is enabled on the column headers
true
#isSearchEnabled
boolean
Decides the search is enabled in columns
#controlledOptions
ControlledOptions<TData>
Controlled options
#isHeadless
boolean
Decides the table is headless (removes headers)
false
#rowKey
string
Row key for the table, the unique identifier for a row, property name
id
#isPaginationEnabled
boolean
Decides the pagination is enabled
false
Pagination
Pagination options
#defaultSorting
SortingState
Default sorting state for the columns
#enableSortingRemoval
boolean
Decides the sorting removal is enabled
true
#enableExpanding
boolean
Row menu option
false
#showExpandIndicator
boolean
Enable/disable expanding for all rows.
true
#rowMenu
RowMenu<TData>
Decides if the icon that shows if a row is expandable is visible
#isLoading
boolean
Decides the global loading state of the table
#isGlobalFilterEnabled
boolean
Is global filtering input enabled
#globalFilterOptions
GlobalFilterOptions<TData>
Global filtering field options
#isFiltersEnabled
boolean
Decides the filtering is enabled on the column headers
#filters
FilterType<TData>[]
Filtering selectors on specific columns
#isClearFiltersEnabled
boolean
Decides if Clear filters button enabled in case there are active filters
#additionalActions
string | ReactElement<any, string | JSXElementConstructor<any>>
Additional custom actions (table header top right)
#className
string
#empty
EmptySettings
Empty table settings and customizations
#isEmptyEnabled
boolean
Decides the empty state is enabled
true
#customStyles
{ actionHeaderStyle?: CSSProperties; tableCellStyles?: SerializedStyles; tableRowStyles?: SerializedStyles; tableHeaderStyles?: SerializedStyles; }
Custom styles for the table
#rowClassName
string | ((record: TData) => string)
Custom row class name for handling custom styling
#isHeaderSticky
boolean
Sets the table to sticky header mode
true
#isFixedLayout
boolean
Sets the table to fixed layout mode
#onSortingChange
(sortingState: SortingState) => void
If provided, this function will be called with the new state when the sorting changes
#onColumnFiltersChange
(columnFiltersState: ColumnFiltersState) => void
If provided, this function will be called with the new state when the column filters change
#customRow
{ isRowCanExpand: (row: Row<TData>) => boolean; renderer: (row: TData) => Element; }
Custom row render options

#Columns

#TableColumnDef props

Extended from TanStack table ColumnDef definition

#id
Required
string
Unique identifier for the column - Defaults to undefined
#accessorKey
Required
(string & )
keyof TData - Defaults to The key for the data from the datasource objects
JSX.Element
The header to display for the column - Defaults to undefined
#isFixed
boolean
Decides if the column is fixed - Defaults to false
#isCompact
boolean
Column inherits compact style - Defaults to false
#isLoading
boolean
Custom loading function for the column - Defaults to undefined
#headerAlign
CSSProperties['justifyContent']
Alignment for the header - Defaults to undefined
#cellAlign
CSSProperties['textAlign']
Alignment for the cells - Defaults to undefined
#size
number
Size for the column - Defaults to undefined
#minSize
number
Min size for the column - Defaults to undefined
#maxSize
number
Max size for the column - Defaults to undefined
#enableGlobalFilter
boolean
Enable global filter on column - Defaults to false
#filterFn
FilterFnOption<TData>
Filter function for the column - Defaults to undefined
#cell
JSX.Element
Custom render function for the cells - Defaults to undefined
#enableSorting
boolean
Decides if sorting is enabled on column - Defaults to true

Read about the built-in FilterFn functions here

Table column example

{ id: 'displayName', header: () => <Translation path="sites.thName" />, accessorKey: 'displayName', isFixed, minSize: 170, maxSize: 500, enableGlobalFilter: true, filterFn: (row, _, term) => row.original.siteLabels?.some(({ name }) => name === term), cell: ({ row }) => { return ( <DisplayName site={row.original} idCompany={idCompany} dataTest="table-siteName" /> ) }, }

#Filters

#FilterType props

#filterOptions
Array<FilterOption>
The list for the selectable options - Defaults to undefined
#column
string
The column which the filter belongs to - Defaults to undefined
#allItemsText
string
All items text in the selectors - Defaults to undefined
#defaultValue
boolean
Default selected value - Defaults to undefined
#additionalContainerStyle
CSSProperties['justifyContent']
Additional style for the selector - Defaults to undefined
#tooltipText
ReactNode
Tooltip for the selector - Defaults to undefined

FilterOption props

#value
string
The value for the selected option - Defaults to undefined
#label
string
The text for the option - Defaults to undefined
#isDisabled
boolean
Decides if the option is disabled - Defaults to false
import { Table, Tag } from '@kinsta/stratus' import type { TableColumnDef, } from '@kinsta/stratus' export type Person = { id: number firstName: string lastName: string } export const TableExample = (): JSX.Element => { export const hobbyFilterOptions = [ { label: 'reading', value: 'reading', }, { label: 'swimming', value: 'swimming', }, { label: 'movies', value: 'movies', }, { label: 'hiking', value: 'hiking', }, ] const data = Person[] = [ { id: 1, firstName: 'John', lastName: 'Doe', hobbies: ['reading', 'swimming'], }, { id: 2, firstName: 'Jane', lastName: 'Doe', hobbies: ['movies', 'hiking'], }, { id: 3, firstName: 'John', lastName: 'Smith', hobbies: ['reading', 'hiking'], }, { id: 4, firstName: 'Jane', lastName: 'Smith', hobbies: ['swimming', 'movies'], }, ] const hobbyFilter: CustomFilterFn<Person> = (row, _, value) => { return row.original.hobbies?.some(hobby => hobby.includes(value.toLowerCase()) ) } const columns: () => TableColumnDef<Person>[] = () => [{ id: 'firstName' header: 'First name', accessorKey: 'firstName', cell: ({ row }) => ( <> {row.original.firstName} <div> {row.original.hobbies.map(h => ( <Tag key={h}>{h}</Tag> ))} </div> </> ), filterFn: hobbyFilter, }, { id: 'lastName', header: 'Last name', accessorKey: 'lastName', }, ] return ( <Table<Person> columns={columns} data={data} isFiltersEnabled filters={[ { allItemsText: 'All hobbies', filterOptions: hobbyFilterOptions, column: 'firstName', }, ]} /> ) }

#Global filters

GlobalFilterOptions props

#hasAutoFocus
boolean
The value for the selected option - Defaults to undefined
#placeholder
ReactElement[]
string[] - Defaults to string
#onChange
(value: string) => void
Decides if the option is disabled - Defaults to false
#globalFilterFn
FilterFn<TData>
Custom filter function for global filtering - Defaults to includesString
#isDisabled
boolean
Decides if the option is disabled - Defaults to false

Read about the built-in FilterFn here

import { Table } from '@kinsta/stratus' import type { TableColumnDef, } from '@kinsta/stratus' type Person = { id: number firstName: string lastName: string } export const TableExample = (): JSX.Element => { const columns: () => TableColumnDef<Person>[] = () => [{ id: 'firstName' header: 'First name', accessorKey: 'firstName', // this column will be filtered by the global filter enableGlobalFilter: true, }, { id: 'lastName', header: 'Last name', accessorKey: 'lastName', enableGlobalFilter: true, }, ] const data = Person[] = [ { id: 1, firstName: 'John', lastName: 'Doe', }, { id: 2, firstName: 'Jane', lastName: 'Doe', }, { id: 3, firstName: 'John', lastName: 'Smith', }, { id: 4, firstName: 'Jane', lastName: 'Smith', }, ] return ( <Table<Person> columns={columns} data={data} isGlobalFilterEnabled globalFilterOptions = {{ placeholder: 'Search for first name or last name...', }} // if there is no data for the global filter search term empty=(globalFilter, resetFilters) => ( <> {`No Data for the ${globalFilter} search term`} <div> <Button onClick={() => { resetFilters() }} > Reset filters </Button> </div> </> ) /> ) }

#Sorting

Sorting is enabled by default on columns use the enableSorting prop to disable it.

defaultSorting prop

defaultSorting prop uses the SortingState

#id
string
The id of the sorted column - Defaults to undefined
#desc
boolean
Decides if the sorting direction is desc - Defaults to undefined
import { Table } from '@kinsta/stratus' import type { TableColumnDef, } from '@kinsta/stratus' type Person = { id: number firstName: string lastName: string } export const TableExample = (): JSX.Element => { const columns: () => TableColumnDef<Person>[] = () => [{ id: 'firstName' header: 'First name', accessorKey: 'firstName', }, { id: 'lastName', header: 'Last name', accessorKey: 'lastName', //this column can not be sorted enableSorting: false, }, ] const data = Person[] = [ { id: 1, firstName: 'John', lastName: 'Doe', }, { id: 2, firstName: 'Jane', lastName: 'Doe', }, { id: 3, firstName: 'John', lastName: 'Smith', }, { id: 4, firstName: 'Jane', lastName: 'Smith', }, ] return ( <Table<Person> columns={columns} data={data} defaultSorting={[ { id: 'firstName', desc: false, }, ]} /> ) }

#Additional actions

These are custom actions that can be added to the table. They are rendered in the table header.

import { Table, Button } from '@kinsta/stratus' import type { TableColumnDef, } from '@kinsta/stratus' export type Person = { id: number firstName: string lastName: string } export const TableExample = (): JSX.Element => { const columns: () => TableColumnDef<Person>[] = () => [{ id: 'firstName' header: 'First name', accessorKey: 'firstName', }, { id: 'lastName', header: 'Last name', accessorKey: 'lastName', }, ] const data = Person[] = [ { id: 1, firstName: 'John', lastName: 'Doe', }, { id: 2, firstName: 'Jane', lastName: 'Doe', }, { id: 3, firstName: 'John', lastName: 'Smith', }, { id: 4, firstName: 'Jane', lastName: 'Smith', }, ] return ( <Table<Person> columns={columns} data={data} additionalActions=( <> <Button type="primary" onClick={action(`onClick:additionalActionButton1`)} > Action 1 </Button> <Button type="secondary" onClick={action(`onClick:additionalActionButton2`)} > Action 2 </Button> </> ), /> ) }

#Row menu

#RowMenu props

#isDisabled
(data: TData) => boolean
Decides if the row menu is enabled or not - Defaults to undefined
#items
RowMenuItem<TData>[]
The menu item list - Defaults to undefined

RowMenuItem props

#label
ReactNode
Content for the menu item - Defaults to undefined
#isDisabled
(record: TData) => boolean
Decides if the item is enabled or not - Defaults to undefined
#onSelect
(record: TData) => void
Custom action function for the item - Defaults to undefined
#isHidden
(record: TData) => boolean
Decides if the item is hidden or not - Defaults to undefined
import { Table, Button } from '@kinsta/stratus' import type { TableColumnDef, } from '@kinsta/stratus' export type Person = { id: number firstName: string lastName: string } export const TableExample = (): JSX.Element => { const columns: () => TableColumnDef<Person>[] = () => [{ id: 'firstName' header: 'First name', accessorKey: 'firstName', }, { id: 'lastName', header: 'Last name', accessorKey: 'lastName', }, ] const data = Person[] = [ { id: 1, firstName: 'John', lastName: 'Doe', }, { id: 2, firstName: 'Jane', lastName: 'Doe', }, { id: 3, firstName: 'John', lastName: 'Smith', }, { id: 4, firstName: 'Jane', lastName: 'Smith', }, ] return ( <Table<Person> columns={columns} data={data} rowMenu={{ isDisabled: () => false, items: [ { label: 'Menu item 1', }, { label: 'Menu item action', onSelect: () => {doSomething()}, }, { label: 'Disabled menu item', isDisabled: () => { return true }, }, ], }}, /> ) }

#MultiSelect

#MultiSelect props

#isRowDisabled
(data: TData) => boolean
Decides if the multiselect is enabled or not on a row - Defaults to undefined
#selectionLabel
(count: number) => ReactNode
The text to show in the table header if rows are selected - Defaults to undefined
#onChange
(selectedRows: TData[]) => void
Custom function if the selected rows are chenged - Defaults to undefined
#actions
MultiSelectActionButtonProps<TData>[]
The list of actions to show if rows are selected - Defaults to undefined
#onCheckboxClick
(data: TData[]) => void
Custom action if the selected state changed - Defaults to undefined
#actionsDropdownPlaceholder
string
Custom placeholder for the Actions dropdown when more than 3 actions are available - Defaults to "Please select an option"

MultiSelectActionButtonProps props

#label
(selectedRows: TData[]) => ReactNode
Label text for the button - Defaults to undefined
#onClick
(selectedRows: TData[]) => void
The custom action for the button - Defaults to undefined
#isDisabled
(selectedRows: TData[]) => boolean
Decides if the button is enabled or not - Defaults to undefined
#tooltipText
(selectedRows: TData[]) => ReactNode
Tooltip for the button - Defaults to undefined

#Simple MultiSelect

import { Table, Button } from '@kinsta/stratus' import type { TableColumnDef, } from '@kinsta/stratus' export type Person = { id: number firstName: string lastName: string } export const TableExample = (): JSX.Element => { const columns: () => TableColumnDef<Person>[] = () => [{ id: 'firstName' header: 'First name', accessorKey: 'firstName', }, { id: 'lastName', header: 'Last name', accessorKey: 'lastName', }, ] const data = Person[] = [ { id: 1, firstName: 'John', lastName: 'Doe', }, { id: 2, firstName: 'Jane', lastName: 'Doe', }, { id: 3, firstName: 'John', lastName: 'Smith', }, { id: 4, firstName: 'Jane', lastName: 'Smith', }, ] return ( <Table<Person> columns={columns} data={data} multiselect={{ isDisabled: () => false, selectionLabel: function label(count) { return <span>{`selected rows: ${count}`}</span> }, actions: [ { type: 'danger', onClick: action(`onClick:actionButton`), label: rows => <span>{`Delete ${rows.length}`}</span>, }, ], }}, /> ) }

#Simple MultiSelect with more than 3 actions

import { Table, Button } from '@kinsta/stratus' import type { TableColumnDef, } from '@kinsta/stratus' export type Person = { id: number firstName: string lastName: string } export const TableExample = (): JSX.Element => { const columns: () => TableColumnDef<Person>[] = () => [{ id: 'firstName' header: 'First name', accessorKey: 'firstName', }, { id: 'lastName', header: 'Last name', accessorKey: 'lastName', }, ] const data = Person[] = [ { id: 1, firstName: 'John', lastName: 'Doe', }, { id: 2, firstName: 'Jane', lastName: 'Doe', }, { id: 3, firstName: 'John', lastName: 'Smith', }, { id: 4, firstName: 'Jane', lastName: 'Smith', }, ] return ( <Table<Person> columns={columns} data={data} multiselect={{ isDisabled: () => false, selectionLabel: function label(count) { return <span>{`selected rows: ${count}`}</span> }, actionsDropdownPlaceholder: 'Actions', actions: [ { onClick: action(`onClick:action1`), label: () => <span>Action 1</span>, }, { onClick: action(`onClick:action2`), label: () => <span>Action 2</span>, }, { onClick: action(`onClick:action3`), label: () => <span>Action 3</span>, }, { onClick: action(`onClick:action4`), label: () => <span>Action 4</span>, }, ], }}, /> ) }

#Controlled MultiSelect

Controlled example. To use this feature you have to set the isControlled prop to true.

import { Table, Button } from '@kinsta/stratus' import type { TableColumnDef, } from '@kinsta/stratus' export type Person = { id: number firstName: string lastName: string } export const TableExample = (): JSX.Element => { const defaultState = { '1': true } //select the first row by default // create a state for the row selection const [rowSelection, setRowSelection] = useState<RowSelection>(defaultState) // create the controlled options const controlledOptions = { onRowSelectionChange: setRowSelection, state: { rowSelection, }, } const columns: () => TableColumnDef<Person>[] = () => [{ id: 'firstName' header: 'First name', accessorKey: 'firstName', }, { id: 'lastName', header: 'Last name', accessorKey: 'lastName', }, ] const data = Person[] = [ { id: 1, firstName: 'John', lastName: 'Doe', }, { id: 2, firstName: 'Jane', lastName: 'Doe', }, { id: 3, firstName: 'John', lastName: 'Smith', }, { id: 4, firstName: 'Jane', lastName: 'Smith', }, ] return ( <Table<Person> columns={columns} data={data} isControlled controlledOptions={controlledOptions} multiselect={{ isDisabled: () => false, selectionLabel: function label(count) { return <span>{`selected rows: ${count}`}</span> }, actions: [ { type: 'danger', onClick: action(`onClick:actionButton`), label: rows => <span>{`Delete ${rows.length}`}</span>, }, ], }}, /> ) }

#Pagination

#pagination

#pageSizes
number[]
Page size options - Defaults to undefined
#showPageSizes
boolean
Show page sizes or not - Defaults to false
#showGotoPage
boolean
Show goto page - Defaults to undefined
#showPageInfo
boolean
Show page info - Defaults to undefined
#showSteppers
boolean
Show steppers - Defaults to undefined
#showFirstLast
boolean
Show first/last page link - Defaults to undefined
#defaultPageSize
number
Sets the default page size - Defaults to undefined
#defaultPageIndex
number
Sets the initial page - Defaults to undefined
#onPaginationChanged
(paginationAction: PaginationAction) => void
Triggered if page changed - Defaults to undefined

#Expanding

Extended from TanStack table Expanded APIs.

#Data structure

To be able to display subRows, the data structure has to be nested. The subRows property is an array of the same type as the parent row. Each subRow should have a unique id for the expanding to work properly.

type Person = { id: number firstName: string lastName: string subRows?: Person[] }

#Table Props

#enableExpanding
boolean
Enables/disables of expansion of rows - Defaults to false
#showExpandIndicator
boolean
Show/hide the expand indicator icon - Defaults to true
#expandOnRowClick
boolean
Expand row on row click - Defaults to true
#isExpandedByDefault
boolean
Expand row by default - Defaults to false
#subRowCellCustomStyles
SerializedStyles
Custom styles for the child cells - Defaults to undefined

#Row

#toggleExpanded
(expanded?: boolean) => void
Toggles the expanded state (or sets it if expanded is provided) for the row. - Defaults to undefined
#getIsExpanded
() => boolean
Returns whether the row is expanded. - Defaults to undefined
#getIsAllParentsExpanded
() => boolean
Returns whether all parent rows of the row are expanded. - Defaults to undefined
#getCanExpand
() => boolean
Returns whether the row can be expanded. - Defaults to undefined
#getToggleExpandedHandler
() => () => void
Returns a function that can be used to toggle the expanded state of the row. This function can be used to bind to an event handler to a button. - Defaults to undefined

#Simple Extended Table

import { Table } from '@kinsta/stratus' import type { TableColumnDef, } from '@kinsta/stratus' type Person = { id: number firstName: string lastName: string subRows?: Person[] } export const TableExample = (): JSX.Element => { const data: Person[] = [ { id: 1, firstName: 'tanner', lastName: 'linsley', subRows: [ { id: 3, firstName: 'adam', lastName: 'smith', }, ], }, { id: 2, firstName: 'tandy', lastName: 'miller', }, ] const columns: TableColumnDef<Person>[] = [ { id: 'firstName', header: 'First name', accessorKey: 'firstName', }, { id: 'lastName', header: 'Last name', accessorKey: 'lastName', }, ] return ( <Table<Person> columns={columns} data={data} enableExpanding /> ) }

#Custom Expanding

#Usage

import { Table } from '@kinsta/stratus' import type { TableColumnDef, } from '@kinsta/stratus' type Project = { id: number projectName: string status: string } type Person = { id: number firstName: string lastName: string nestedColumns?: TableColumnDef<Project>[] nestedData: { id: number projectName: string status: string }[] } const isRowCanExpand = <TData extends ExpandableCustomTableData>( row: Row<TData> ) => Boolean(row.original.nestedColumns && row.original.nestedData) const customTableSubRowRenderer = < TData extends ExpandableCustomTableData >( data: TData ) => { return ( <> <NotePanel type="warning" style={{ marginBottom: space[200] }}> This is some test note panel </NotePanel> <Table key={data.nestedColumns?.[0].id} id="nestedTable" columns={data.nestedColumns ?? []} data={data.nestedData ?? []} rowKey="test" /> </> ) } export const TableExample = (): JSX.Element => { const data: Person[] = [ { id: 1, firstName: 'tanner', lastName: 'linsley', nestedColumns: [ { id: 'projectName', header: 'Project name', accessorKey: 'projectName', }, { id: 'status', header: 'Status', accessorKey: 'status', }, ], nestedData: [ { id: 1, projectName: 'Project 1', status: 'Active', }, { id: 2, projectName: 'Project 2', status: 'Inactive', }, ], }, { id: 2, firstName: 'tandy', lastName: 'miller', nestedColumns: [ { id: 'projectName', header: 'Project name', accessorKey: 'projectName', }, { id: 'status', header: 'Status', accessorKey: 'status', }, ], nestedData: [ { id: 3, projectName: 'Project 3', status: 'Active', }, { id: 4, projectName: 'Project 4', status: 'Inactive', }, ], }, ] const columns: TableColumnDef<Person>[] = [ { id: 'firstName', header: 'First name', accessorKey: 'firstName', }, { id: 'lastName', header: 'Last name', accessorKey: 'lastName', }, ] return ( <Table<Person> columns={columns} data={data} enableExpanding expandOnRowClick customRow={{ isRowCanExpand, renderer: customTableSubRowRenderer, }} /> ) }