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
#Columns
#TableColumnDef props
Extended from TanStack table ColumnDef definition
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
FilterOption props
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
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
desc
- Defaults to undefinedimport { 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
RowMenuItem props
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
MultiSelectActionButtonProps props
#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
#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
#Row
#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,
}}
/>
)
}