react-table
React Table Implementation
This project uses @tanstack/react-table v8 and renders with the project’s Table primitives in @/modules/common/components/ui/table (shadcn-based).
Architecture overview
| Layer | Location | Responsibility |
|---|---|---|
| Column config | constants/*TableConfig.tsx |
ColumnDef<T>[]: header, accessor, cell, filterFn, size, etc. |
| Container | containers/*Container.tsx |
useReactTable, data source, optional virtual/selection/filter |
| Common component | common/components/ui/data-table.tsx |
Simple tables can use <DataTable columns={} data={} /> |
| Table UI | common/components/ui/table |
Table, TableHeader, TableBody, TableRow / SelectableTableRow, TableHead, TableCell |
1. Column configuration
- Type:
ColumnDef<TData>[]from@tanstack/react-table. - Common properties:
id: unique identifier (optional; otherwise derived from accessor)header: string or() => ReactNode(use a function when composing UI like sort buttons)accessorKeyoraccessorFn: value accessorcell:({ row }) => ReactNode, typically viarow.getValue<T>(key)orrow.originalsize: number (px). Used for fixed widths and virtualized layoutsfilterFn: custom filter function (see below)enableSorting,sortingFn: sorting controls
Example (simplified):
// constants/exampleTableConfig.tsx
import type { ColumnDef } from '@tanstack/react-table';
export const exampleTableColumns: ColumnDef<ExampleRow>[] = [
{ header: 'Name', accessorKey: 'name', cell: ({ row }) => row.getValue('name') },
{
id: 'amount',
header: 'Amount',
accessorFn: (row) => row.amount,
cell: ({ row }) => <span>{row.original.amount}</span>,
size: 120,
},
];
2. Creating a table instance
In a container, call useReactTable with at least data, columns, and getCoreRowModel: getCoreRowModel().
import {
flexRender,
getCoreRowModel,
useReactTable,
} from '@tanstack/react-table';
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
});
Add advanced features only when needed:
- Sorting:
getSortedRowModel: getSortedRowModel() - Filtering:
getFilteredRowModel: getFilteredRowModel(), optionallyfilterFns: {}(or a map from filter name to fn) - Row selection:
enableRowSelection: true,enableMultiRowSelection: true/false, usingrow.toggleSelected()andtable.getSelectedRowModel().rows
3. Rendering
Render headers and cells using the project Table primitives and flexRender.
Header:
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id}>
{headerGroup.headers.map((header) => (
<TableHead key={header.id} style={{ width: header.getSize() }}>
{header.isPlaceholder
? null
: flexRender(header.column.columnDef.header, header.getContext())}
</TableHead>
))}
</TableRow>
))}
</TableHeader>
Body:
<TableBody>
{table.getRowModel().rows.map((row) => (
<TableRow key={row.id} data-state={row.getIsSelected() && 'selected'}>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))}
</TableBody>
For empty states, render a single <TableRow> with <TableCell colSpan={columns.length}>No results.</TableCell>.
4. Optional patterns
Simple tables: use DataTable
If you don’t need row selection, virtualization, or custom filters:
import { DataTable } from '@/modules/common/components/ui/data-table';
<DataTable columns={columns} data={data} />
Row selection
- Enable selection with
enableRowSelection: trueand setenableMultiRowSelectiontofalse(single) ortrue(multi). - Use
SelectableTableRow; callrow.toggleSelected()on click; style selected state viadata-state={row.getIsSelected() && 'selected'}. - “Select all”: render a checkbox in the header using
table.getIsAllRowsSelected()andtable.getToggleAllRowsSelectedHandler(). - Get selected rows via
table.getSelectedRowModel().rows.map((row) => row.original).
Virtualized body
- Use the project
useStableVirtualizer(built on@tanstack/react-virtual), providingcount: rows.length, a stablegetScrollElement(outer scroll container ref),estimateSize, optionalmeasureElement, andoverscan. - Use the same scroll container ref for
getScrollElement. - Only render
rowVirtualizer.getVirtualItems(). Position rows withtransform: translateY(${virtualRow.start}px)and set the body container height torowVirtualizer.getTotalSize(). - When data (or
rows.length) changes, akeyor state bump may be used to force recalculation (seeDiscoverTableContainer/PublicChannelContainer).
Custom filtering (filterFn)
- Filter function signature:
(row, columnId, filterValue, addMeta) => boolean(seeRowfrom@tanstack/react-table). - Set
filterFn: customizedXxxFilteron the column definition (e.g.customizedTimeFilter,customizedAddressFilter). - Update filters from the container via
table.getColumn(columnId)?.setFilterValue(value)(often driven by filter UI such as time/address dialogs). - Keep reusable filter implementations in
utils/tableFilters.ts, then import them into column configs.
Sorting
- Add
getSortedRowModel: getSortedRowModel(). - When a header needs sorting UI, use the project
SortButtonwithonSort={() => column.toggleSorting()}andsortDirection={column.getIsSorted()}. - Columns can set
enableSorting: true,sortingFn: 'auto', or a customsortingFn.
5. File & type conventions
- Column configs: live under
constants/<feature>TableConfig.tsx. ExportColumnDef<T>[]or a factory likecreateXxxTableConfig(...). Export row types asXxxRow/XxxItem. - Containers: fetch/derive data (react-query, atoms, etc.), build
data+columns, calluseReactTable, then render with Table primitives +flexRender. UseuseRefto hold the table instance or scroll container for virtualization/filter wiring. - Table primitives: use
SelectableTableRowfor selectable rows; otherwiseTableRow. For virtualization,TableBodyoften usesdisplay: gridandposition: relative, while rows useposition: absolute+translateY.
6. Checklist (when adding/modifying a table)
- Column configs live in
constants/*TableConfig.tsxand are typed asColumnDef<T>[] - The container calls
useReactTablewith at leastdata,columns, andgetCoreRowModel() - Rendering uses
Table/TableHeader/TableBody/TableRow(orSelectableTableRow) andTableHead/TableCellwithflexRender - Sorting: add
getSortedRowModel()and header UI (projectSortButton) where needed - Filtering: add
getFilteredRowModel(), setfilterFnon columns, and update values viagetColumn(id)?.setFilterValue(...) - Large datasets: consider virtualization (
useStableVirtualizer+ a stable scroll container) - Selection: use
SelectableTableRow+row.toggleSelected()and read selection viagetSelectedRowModel()
How to Use
Read individual reference files for detailed code and patterns:
references/README.md
references/minimal-data-table.md
references/row-selection.md
references/sorting-virtualized.md
references/filtering.md
references/table-filters.md
references/multi-select-header.md
references/table-primitives.md
Each reference file contains focused documentation and code examples for that topic. When implementing or modifying tables, load these as needed instead of main-project paths.
More from tianyili/skills
react-architect-skills
React and TanStack Router folder structure and feature-module architecture. Use when writing, reviewing, or refactoring React code for structure, naming, colocation, encapsulation, and layer separation. Triggers on React folder structure, naming rules, module boundaries, or architecture decisions.
34vercel-react-only-best-practices
React performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React code to ensure optimal performance patterns. Triggers on tasks involving React components, data fetching, bundle optimization, or performance improvements.
21skill-creator
Guide for creating effective skills. This skill should be used when users want to create a new skill (or update an existing skill) that extends Claude's capabilities with specialized knowledge, workflows, or tool integrations.
5zustand
Use and structure Zustand stores for React and vanilla JS state management. Use when the user mentions Zustand, needs a store pattern, global state, persist state, or migrating from Redux/Context.
4skill-judge
Evaluate Agent Skill design quality against official specifications and best practices. Use when reviewing, auditing, or improving SKILL.md files and skill packages. Provides multi-dimensional scoring and actionable improvement suggestions.
1