Data Table
Anatomy
Section titled “Anatomy”<DataTable columns={columns} data={data} />The DataTable component provides advanced table functionality including sorting and custom column rendering. It’s built on top of TanStack Table and provides a simpler API for common use cases.
To create a data table, use the <DataTable> component with columns and data props.
import { DataTable } from "stylus-ui/DataTable";
const data = [ { id: 1, name: "Thomas Kao", role: "Creator", views: "70.3k", }, { id: 2, name: "Aleksandar Radic", role: "Team Admin", views: "52.4k", }, { id: 3, name: "Maria Mi", role: "Team Admin", views: "20.3k", },];
const columns = [ { accessorKey: "id", header: "ID", }, { accessorKey: "name", header: "Name", }, { accessorKey: "role", header: "Role", }, { accessorKey: "views", header: "Views", },];
export default () => <DataTable columns={columns} data={data} />;Custom cell and header rendering
Section titled “Custom cell and header rendering”You can customize how each cell is rendered by passing a render function to header or cell in your column definition.
import { Avatar } from "stylus-ui/Avatar";import { DataTable } from "stylus-ui/DataTable";import { TableHead } from "stylus-ui/Table";
const data = [ { id: 1, name: "Thomas Kao", role: "Creator", lastActive: "Jul 01, 2024", views: "70.3k", }, { id: 2, name: "Aleksandar Radic", role: "Team Admin", lastActive: "Jul 01, 2024", views: "52.4k", }, { id: 3, name: "Maria Mi", role: "Team Admin", lastActive: "Jul 01, 2024", views: "20.3k", },];
const columns = [ { accessorKey: "id", header: "ID", }, { accessorKey: "name", header: "Name", cell: (props) => ( <div className="flex items-center"> <Avatar size="xs">{props.getValue()[0]}</Avatar> <span className="ml-2.5">{props.getValue()}</span> </div> ), }, { accessorKey: "role", header: "Role", }, { accessorKey: "lastActive", header: "Last Active", cell: (props) => ( <time dateTime={props.getValue()}>{props.getValue()}</time> ), }, { accessorKey: "views", header: () => <TableHead className="text-right">Views</TableHead>, cell: (props) => <div className="text-right">{props.getValue()}</div>, },];
export default () => <DataTable columns={columns} data={data} />;Sortable columns
Section titled “Sortable columns”Make columns sortable by using the DataTableSortingHeader component.
import { DataTable, DataTableSortingHeader } from "stylus-ui/DataTable";
const data = [ { id: 1, name: "Thomas Kao", role: "Creator", views: "70.3k", }, { id: 2, name: "Aleksandar Radic", role: "Team Admin", views: "52.4k", }, { id: 3, name: "Maria Mi", role: "Team Admin", views: "20.3k", },];
const columns = [ { accessorKey: "id", header: ({ column }) => ( <DataTableSortingHeader column={column} title="ID" /> ), }, { accessorKey: "name", header: ({ column }) => ( <DataTableSortingHeader column={column} title="Name" /> ), }, { accessorKey: "role", header: "Role", }, { accessorKey: "views", header: ({ column }) => ( <DataTableSortingHeader column={column} title="Views" /> ), },];
export default () => <DataTable columns={columns} data={data} />;Empty state
Section titled “Empty state”The DataTable handles empty data arrays gracefully by displaying a “No data available” message.
import { DataTable } from "stylus-ui/DataTable";
const columns = [ { accessorKey: "id", header: "ID", }, { accessorKey: "name", header: "Name", }, { accessorKey: "role", header: "Role", },];
export default () => <DataTable columns={columns} data={[]} />;Row click handling
Section titled “Row click handling”You can handle row clicks by providing an onRowClick callback. The callback receives the TanStack Table row object. Clicks on interactive elements (buttons, links, inputs, etc.) are automatically ignored.
import { Card } from "stylus-ui/Card";import { DataTable } from "stylus-ui/DataTable";import { useState } from "react";
const data = [ { id: 1, name: "Thomas Kao", role: "Creator", views: "70.3k", }, { id: 2, name: "Aleksandar Radic", role: "Team Admin", views: "52.4k", }, { id: 3, name: "Maria Mi", role: "Team Admin", views: "20.3k", },];
const columns = [ { accessorKey: "id", header: "ID", }, { accessorKey: "name", header: "Name", }, { accessorKey: "role", header: "Role", }, { accessorKey: "views", header: "Views", },];
export default () => { const [selectedRow, setSelectedRow] = useState(null);
return ( <div className="flex w-full flex-col gap-2"> <DataTable columns={columns} data={data} onRowClick={(row) => setSelectedRow(row.original)} /> <Card> Selected:{" "} {selectedRow ? `${selectedRow.name} (${selectedRow.role})` : "None"} </Card> </div> );};Custom row styling
Section titled “Custom row styling”You can apply custom styling to all rows using the rowClassName prop. This is useful for adding hover effects or other row-level styles.
import { DataTable } from "stylus-ui/DataTable";
const data = [ { id: 1, name: "Thomas Kao", role: "Creator", views: "70.3k", }, { id: 2, name: "Aleksandar Radic", role: "Team Admin", views: "52.4k", }, { id: 3, name: "Maria Mi", role: "Team Admin", views: "20.3k", },];
const columns = [ { accessorKey: "id", header: "ID", }, { accessorKey: "name", header: "Name", }, { accessorKey: "role", header: "Role", }, { accessorKey: "views", header: "Views", },];
export default () => ( <DataTable columns={columns} data={data} rowClassName="cursor-pointer hover:bg-blue-50" onRowClick={(row) => console.log("Clicked:", row.original)} />);Custom scroll area
Section titled “Custom scroll area”You can customize the scroll behavior by passing props to the underlying ScrollArea component using scrollAreaProps. This is useful for controlling height, scrollbar visibility, and other scroll-related behavior.
import { DataTable } from "stylus-ui/DataTable";import { TableHead } from "stylus-ui/Table";
const data = [ { id: 1, name: "Thomas Kao", role: "Creator", views: "70.3k", }, { id: 2, name: "Aleksandar Radic", role: "Team Admin", views: "52.4k", }, { id: 3, name: "Maria Mi", role: "Team Admin", views: "20.3k", }, { id: 4, name: "Jane Smith", role: "Viewer", views: "15.2k", }, { id: 5, name: "John Doe", role: "Creator", views: "45.8k", },];
const columns = [ { accessorKey: "id", header: "ID", }, { accessorKey: "name", header: () => <TableHead className="min-w-[300px]">Name</TableHead>, }, { accessorKey: "role", header: () => <TableHead className="min-w-[300px]">Role</TableHead>, }, { accessorKey: "views", header: "Views", },];
export default () => ( <DataTable columns={columns} data={data} scrollAreaProps={{ type: "auto", }} />);API Reference
Section titled “API Reference”DataTable
Section titled “DataTable”A table displaying filterable, sortable data in rows and columns.
columns
data
The data for the table to display. This array should match the type you provided to table.setRowType<...>. Columns can access this data via string/index or a functional accessor. When the data option changes reference, the table will reprocess the data.
@link API Docs
@link Guide
_features
aggregationFns
autoResetAll
autoResetExpanded
Enable this setting to automatically reset the expanded state of the table when expanding state changes. @link API Docs @link Guide
autoResetPageIndex
If set to true, pagination will be reset to the first page when page-altering state changes eg. data is updated, filters change, grouping changes, etc.
@link API Docs
@link Guide
columnResizeDirection
Enables or disables right-to-left support for resizing the column. defaults to ‘ltr’. @link API Docs @link Guide
columnResizeMode
Determines when the columnSizing state is updated. onChange updates the state when the user is dragging the resize handle. onEnd updates the state when the user releases the resize handle.
@link API Docs
@link Guide
debugAll
Set this option to true to output all debugging information to the console.
@link API Docs
@link Guide
debugCells
Set this option to true to output cell debugging information to the console.
@link [API Docs](https://tanstack.com/table/v8/docs/api/core/table#debugcells]
@link Guide
debugColumns
Set this option to true to output column debugging information to the console.
@link API Docs
@link Guide
debugHeaders
Set this option to true to output header debugging information to the console.
@link API Docs
@link Guide
debugRows
Set this option to true to output row debugging information to the console.
@link API Docs
@link Guide
debugTable
Set this option to true to output table debugging information to the console.
@link API Docs
@link Guide
defaultColumn
enableColumnFilters
enableColumnPinning
enableColumnResizing
enableExpanding
enableFilters
enableGlobalFilter
enableGrouping
enableHiding
enableMultiRemove
enableMultiRowSelection
enableMultiSort
enablePinning
@deprecated Use enableColumnPinning or enableRowPinning instead.
Enables/disables all pinning for the table. Defaults to true.
@link API Docs
@link Guide
enableRowPinning
enableRowSelection
enableSorting
enableSortingRemoval
Enables/Disables the ability to remove sorting for the table.
enableSubRowSelection
Enables/disables automatic sub-row selection when a parent row is selected, or a function that enables/disables automatic sub-row selection for each row. (Use in combination with expanding or grouping features) @link API Docs @link Guide
filterFns
filterFromLeafRows
By default, filtering is done from parent rows down (so if a parent row is filtered out, all of its children will be filtered out as well). Setting this option to true will cause filtering to be done from leaf rows up (which means parent rows will be included so long as one of their child or grand-child rows is also included).
@link API Docs
@link Guide
getColumnCanGlobalFilter
If provided, this function will be called with the column and should return true or false to indicate whether this column should be used for global filtering.
This is useful if the column can contain data that is not string or number (i.e. undefined).
@link API Docs
@link Guide
getCoreRowModel
Override default core row model (optional).
getExpandedRowModel
This function is responsible for returning the expanded row model. If this function is not provided, the table will not expand rows. You can use the default exported getExpandedRowModel function to get the expanded row model or implement your own.
@link API Docs
@link Guide
getFacetedMinMaxValues
getFacetedRowModel
getFacetedUniqueValues
getFilteredRowModel
If provided, this function is called once per table and should return a new function which will calculate and return the row model for the table when it’s filtered.
- For server-side filtering, this function is unnecessary and can be ignored since the server should already return the filtered row model.
- For client-side filtering, this function is required. A default implementation is provided via any table adapter’s
{ getFilteredRowModel }export. @link API Docs @link Guide
getGroupedRowModel
getIsRowExpanded
If provided, allows you to override the default behavior of determining whether a row is currently expanded. @link API Docs @link Guide
getPaginationRowModel
Returns the row model after pagination has taken place, but no further.
Pagination columns are automatically reordered by default to the start of the columns list. If you would rather remove them or leave them as-is, set the appropriate mode here. @link API Docs @link Guide
getRowCanExpand
If provided, allows you to override the default behavior of determining whether a row can be expanded. @link API Docs @link Guide
getRowId
This optional function is used to derive a unique ID for any given row. If not provided the rows index is used (nested rows join together with . using their grandparents’ index eg. index.index.index). If you need to identify individual rows that are originating from any server-side operations, it’s suggested you use this function to return an ID that makes sense regardless of network IO/ambiguity eg. a userId, taskId, database ID field, etc.
@example getRowId: row => row.userId
@link API Docs
@link Guide
getSortedRowModel
Override default sorted row model (optional).
getSubRows
This optional function is used to access the sub rows for any given row. If you are using nested rows, you will need to use this function to return the sub rows object (or undefined) from the row. @example getSubRows: row => row.subRows @link API Docs @link Guide
globalFilterFn
The filter function to use for global filtering.
groupedColumnMode
Grouping columns are automatically reordered by default to the start of the columns list. If you would rather remove them or leave them as-is, set the appropriate mode here. @link API Docs @link Guide
initialState
Use this option to optionally pass initial state to the table. This state will be used when resetting various table states either automatically by the table (eg. options.autoResetPageIndex) or via functions like table.resetRowSelection(). Most reset function allow you optionally pass a flag to reset to a blank/default state instead of the initial state.
Table state will not be reset when this object changes, which also means that the initial state object does not need to be stable. @link API Docs @link Guide
isMultiSortEvent
Pass a custom function that will be used to determine if a multi-sort event should be triggered. It is passed the event from the sort toggle handler and should return true if the event should trigger a multi-sort.
@link API Docs
@link Guide
keepPinnedRows
When false, pinned rows will not be visible if they are filtered or paginated out of the table. When true, pinned rows will always be visible regardless of filtering or pagination. Defaults to true.
@link API Docs
@link Guide
manualExpanding
Enables manual row expansion. If this is set to true, getExpandedRowModel will not be used to expand rows and you would be expected to perform the expansion in your own data model. This is useful if you are doing server-side expansion.
@link API Docs
@link Guide
manualFiltering
Disables the getFilteredRowModel from being used to filter data. This may be useful if your table needs to dynamically support both client-side and server-side filtering.
@link API Docs
@link Guide
manualGrouping
Enables manual grouping. If this option is set to true, the table will not automatically group rows using getGroupedRowModel() and instead will expect you to manually group the rows before passing them to the table. This is useful if you are doing server-side grouping and aggregation.
@link API Docs
@link Guide
manualPagination
Enables manual pagination. If this option is set to true, the table will not automatically paginate rows using getPaginationRowModel() and instead will expect you to manually paginate the rows before passing them to the table. This is useful if you are doing server-side pagination and aggregation.
@link API Docs
@link Guide
manualSorting
Enables manual sorting for the table. If this is true, you will be expected to sort your data before it is passed to the table. This is useful if you are doing server-side sorting.
@link API Docs
@link Guide
maxLeafRowFilterDepth
By default, filtering is done for all rows (max depth of 100), no matter if they are root level parent rows or the child leaf rows of a parent row. Setting this option to 0 will cause filtering to only be applied to the root level parent rows, with all sub-rows remaining unfiltered. Similarly, setting this option to 1 will cause filtering to only be applied to child leaf rows 1 level deep, and so on.
This is useful for situations where you want a row’s entire child hierarchy to be visible regardless of the applied filter. @link API Docs @link Guide
maxMultiSortColCount
mergeOptions
This option is used to optionally implement the merging of table options. @link API Docs @link Guide
meta
You can pass any object to options.meta and access it anywhere the table is available via table.options.meta.
@link API Docs
@link Guide
onColumnFiltersChange
If provided, this function will be called with an updaterFn when state.columnFilters changes. This overrides the default internal state management, so you will need to persist the state change either fully or partially outside of the table.
@link API Docs
@link Guide
onColumnOrderChange
If provided, this function will be called with an updaterFn when state.columnOrder changes. This overrides the default internal state management, so you will need to persist the state change either fully or partially outside of the table.
@link API Docs
@link Guide
onColumnPinningChange
If provided, this function will be called with an updaterFn when state.columnPinning changes. This overrides the default internal state management, so you will also need to supply state.columnPinning from your own managed state.
@link API Docs
@link Guide
onColumnSizingChange
If provided, this function will be called with an updaterFn when state.columnSizing changes. This overrides the default internal state management, so you will also need to supply state.columnSizing from your own managed state.
@link API Docs
@link Guide
onColumnSizingInfoChange
If provided, this function will be called with an updaterFn when state.columnSizingInfo changes. This overrides the default internal state management, so you will also need to supply state.columnSizingInfo from your own managed state.
@link API Docs
@link Guide
onColumnVisibilityChange
If provided, this function will be called with an updaterFn when state.columnVisibility changes. This overrides the default internal state management, so you will need to persist the state change either fully or partially outside of the table.
@link API Docs
@link Guide
onExpandedChange
This function is called when the expanded table state changes. If a function is provided, you will be responsible for managing this state on your own. To pass the managed state back to the table, use the tableOptions.state.expanded option.
@link API Docs
@link Guide
onGlobalFilterChange
If provided, this function will be called with an updaterFn when state.globalFilter changes. This overrides the default internal state management, so you will need to persist the state change either fully or partially outside of the table.
@link API Docs
@link Guide
onGroupingChange
If this function is provided, it will be called when the grouping state changes and you will be expected to manage the state yourself. You can pass the managed state back to the table via the tableOptions.state.grouping option.
@link API Docs
@link Guide
onPaginationChange
If this function is provided, it will be called when the pagination state changes and you will be expected to manage the state yourself. You can pass the managed state back to the table via the tableOptions.state.pagination option.
@link API Docs
@link Guide
onRowClick
Called when a row is clicked (ignored when clicking buttons/links/inputs).
onRowPinningChange
If provided, this function will be called with an updaterFn when state.rowPinning changes. This overrides the default internal state management, so you will also need to supply state.rowPinning from your own managed state.
@link API Docs
@link Guide
onRowSelectionChange
If provided, this function will be called with an updaterFn when state.rowSelection changes. This overrides the default internal state management, so you will need to persist the state change either fully or partially outside of the table.
@link API Docs
@link Guide
onSortingChange
If provided, this function will be called with an updaterFn when state.sorting changes. This overrides the default internal state management, so you will need to persist the state change either fully or partially outside of the table.
@link API Docs
@link Guide
onStateChange
The onStateChange option can be used to optionally listen to state changes within the table.
@link API Docs
@link Guide
pageCount
When manually controlling pagination, you can supply a total pageCount value to the table if you know it (Or supply a rowCount and pageCount will be calculated). If you do not know how many pages there are, you can set this to -1.
@link API Docs
@link Guide
paginateExpandedRows
If true expanded rows will be paginated along with the rest of the table (which means expanded rows may span multiple pages). If false expanded rows will not be considered for pagination (which means expanded rows will always render on their parents page. This also means more rows will be rendered than the set page size)
@link API Docs
@link Guide
renderFallbackValue
rowClassName
Class name applied to each table row.
rowCount
When manually controlling pagination, you can supply a total rowCount value to the table if you know it. The pageCount can be calculated from this value and the pageSize.
@link API Docs
@link Guide
scrollAreaProps
Props passed to the ScrollArea wrapping the table.
sortDescFirst
If true, all sorts will default to descending as their first toggle state.
@link API Docs
@link Guide
sortingFns
state
The state option can be used to optionally control part or all of the table state. The state you pass here will merge with and overwrite the internal automatically-managed state to produce the final state for the table. You can also listen to state changes via the onStateChange option.
Note: Any state passed in here will override both the internal state and any other
initialStateyou provide. @link API Docs @link Guide
DataTableSortingHeader
Section titled “DataTableSortingHeader” column
TanStack Table column instance (for sort state and toggle).
title
Header label or custom node.
className
Optional class for the header cell.