web-ui-tanstack-table
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseTanStack Table Patterns
TanStack Table 模式汇总
Quick Guide: TanStack Table is a headless UI library for building powerful tables and datagrids. Usehook withuseReactTablefor type-safe column definitions. Import only the row models you need (createColumnHelper,getSortedRowModel, etc.) for tree-shaking. Memoize data and columns withgetFilteredRowModelto prevent infinite re-renders. SetuseMemo,manualPagination,manualSortingtomanualFilteringfor server-side data.true
<critical_requirements>
快速指南: TanStack Table 是一个用于构建功能强大的表格和数据网格的无头UI库。结合Hook 与useReactTable实现类型安全的列定义。仅导入所需的行模型(如createColumnHelper、getSortedRowModel等)以支持摇树优化。使用getFilteredRowModel对数据和列进行记忆化处理,避免无限重渲染。处理服务端数据时,需将useMemo、manualPagination、manualSorting设置为manualFiltering。true
<critical_requirements>
CRITICAL: Before Using This Skill
重要提示:使用此技能之前
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering,, named constants)import type
(You MUST memoize data and columns with - unstable references cause infinite re-renders)
useMemo(You MUST use for type-safe column definitions with proper TValue inference)
createColumnHelper<TData>()(You MUST import row models explicitly - , , etc. - for tree-shaking)
getSortedRowModelgetFilteredRowModel(You MUST use for direct property access and with explicit for computed values)
accessorKeyaccessorFnid(You MUST set , , to for server-side data)
manualPaginationmanualSortingmanualFilteringtrue</critical_requirements>
Auto-detection: TanStack Table, @tanstack/react-table, useReactTable, createColumnHelper, getCoreRowModel, getSortedRowModel, getFilteredRowModel, getPaginationRowModel, ColumnDef, column definitions, table state
When to use:
- Building data tables with sorting, filtering, and pagination
- Implementing server-side data tables with API integration
- Creating tables with row selection and expansion
- Building virtual scrolling tables for large datasets
- Implementing column visibility controls and column ordering
When NOT to use:
- Simple tables without interactive features (use plain HTML tables)
- Tables with fewer than 20 rows and no sorting/filtering needs
- Read-only data display without user interaction
Key patterns covered:
- useReactTable hook setup with type-safe generics
- Column definitions with columnHelper
- Sorting, filtering, pagination (client-side and server-side)
- Row selection, expanding rows, column visibility
- Virtual scrolling, column pinning, column resizing
Detailed Resources:
- examples/core.md - Basic table setup, column definitions, type safety
- examples/sorting.md - Column sorting with custom sort functions
- examples/filtering.md - Column and global filtering
- examples/pagination.md - Client-side pagination
- examples/selection.md - Row selection with bulk actions
- examples/expanding.md - Expandable rows with sub-content
- examples/column-visibility.md - Column visibility toggles
- examples/server-side.md - Server-side data handling
- examples/virtualization.md - Virtual scrolling for large datasets
- examples/column-pinning.md - Sticky pinned columns (left/right)
- examples/column-resizing.md - Performant column resizing with CSS variables
- reference.md - Decision frameworks, checklists, anti-patterns
<philosophy>
所有代码必须遵循 CLAUDE.md 中的项目规范(短横线命名、命名导出、导入顺序、、命名常量)import type
(必须使用 对数据和列进行记忆化处理——不稳定的引用会导致无限重渲染)
useMemo(必须使用 实现类型安全的列定义,并确保正确的 TValue 类型推断)
createColumnHelper<TData>()(必须显式导入行模型——如 、 等——以支持摇树优化)
getSortedRowModelgetFilteredRowModel(直接属性访问必须使用 ,计算值必须使用带显式 的 )
accessorKeyidaccessorFn(处理服务端数据时,必须将 、、 设置为 )
manualPaginationmanualSortingmanualFilteringtrue</critical_requirements>
自动检测关键词: TanStack Table, @tanstack/react-table, useReactTable, createColumnHelper, getCoreRowModel, getSortedRowModel, getFilteredRowModel, getPaginationRowModel, ColumnDef, 列定义, 表格状态
适用场景:
- 构建带有排序、筛选和分页功能的数据表格
- 实现与API集成的服务端数据表格
- 创建支持行选择和展开的表格
- 为大型数据集构建虚拟滚动表格
- 实现列可见性控制和列排序功能
不适用场景:
- 无交互功能的简单表格(使用纯HTML表格即可)
- 行数少于20行且无需排序/筛选的表格
- 无用户交互的只读数据展示
涵盖的核心模式:
- 带类型安全泛型的 useReactTable Hook 配置
- 使用 columnHelper 定义列
- 排序、筛选、分页(客户端和服务端)
- 行选择、行展开、列可见性
- 虚拟滚动、列固定、列宽调整
详细资源:
- examples/core.md - 基础表格配置、列定义、类型安全
- examples/sorting.md - 自定义排序函数的列排序
- examples/filtering.md - 列筛选和全局筛选
- examples/pagination.md - 客户端分页
- examples/selection.md - 支持批量操作的行选择
- examples/expanding.md - 带子内容的可展开行
- examples/column-visibility.md - 列可见性切换
- examples/server-side.md - 服务端数据处理
- examples/virtualization.md - 大型数据集的虚拟滚动
- examples/column-pinning.md - 固定列(左侧/右侧)
- examples/column-resizing.md - 使用CSS变量实现高性能列宽调整
- reference.md - 决策框架、检查清单、反模式
<philosophy>
Philosophy
设计理念
TanStack Table is a headless UI library - it provides the logic for tables without any markup or styles. This gives you complete control over rendering while the library handles complex state management for sorting, filtering, pagination, and more.
Core Principles:
- Headless Architecture - No pre-built components. You own the markup and styling.
- Type Safety - Full TypeScript support with generics for data types.
- Tree-Shakable - Import only what you use. Each feature is a separate row model.
- Framework Agnostic - Same API works across React, Vue, Solid, and Svelte.
- Performant - Optimized for large datasets with virtualization support.
Why Headless?
The headless approach means TanStack Table handles the hard parts (state management, sorting algorithms, pagination logic) while you control presentation. This is ideal when:
- You need custom table designs that don't fit pre-built components
- You're integrating with an existing design system
- You need maximum performance control
<patterns>
TanStack Table 是一个无头UI库——它仅提供表格的逻辑实现,不包含任何标记或样式。这让你完全控制渲染方式,同时由库处理排序、筛选、分页等复杂状态管理。
核心原则:
- 无头架构 - 无预构建组件,你完全掌控标记和样式
- 类型安全 - 全面支持TypeScript泛型,确保数据类型正确
- 摇树优化支持 - 仅导入所需功能,每个特性都是独立的行模型
- 框架无关 - 相同API可在React、Vue、Solid和Svelte中使用
- 高性能 - 针对大型数据集优化,支持虚拟滚动
为什么选择无头架构?
无头架构意味着TanStack Table处理复杂的部分(状态管理、排序算法、分页逻辑),而你负责展示层。这种方式非常适合以下场景:
- 需要自定义表格设计,不适合使用预构建组件
- 与现有设计系统集成
- 需要最大程度控制性能
<patterns>
Core Patterns
核心模式
Pattern 1: Basic Table Setup
模式1:基础表格配置
Set up a type-safe table with and . See examples/core.md for complete implementation.
useReactTablecreateColumnHelpertypescript
const columnHelper = createColumnHelper<User>();
const columns = useMemo(
() => [
columnHelper.accessor("firstName", { header: "First Name" }),
// accessorFn for computed values - MUST include id
columnHelper.accessor((row) => `${row.firstName} ${row.lastName}`, {
id: "fullName",
header: "Full Name",
}),
],
[],
);
const data = useMemo(() => users, [users]);
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
getRowId: (row) => row.id,
});Critical: Memoize both and - unstable references cause infinite re-renders.
columnsdata使用 和 搭建类型安全的表格。完整实现请参考 examples/core.md。
useReactTablecreateColumnHelpertypescript
const columnHelper = createColumnHelper<User>();
const columns = useMemo(
() => [
columnHelper.accessor("firstName", { header: "First Name" }),
// accessorFn 用于计算值 - 必须包含 id
columnHelper.accessor((row) => `${row.firstName} ${row.lastName}`, {
id: "fullName",
header: "Full Name",
}),
],
[],
);
const data = useMemo(() => users, [users]);
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
getRowId: (row) => row.id,
});重要提示: 必须对 和 进行记忆化处理——不稳定的引用会导致无限重渲染。
columnsdataPattern 2: Sorting
模式2:排序
Enable sorting with and controlled state. See examples/sorting.md.
getSortedRowModeltypescript
const [sorting, setSorting] = useState<SortingState>([]);
const table = useReactTable({
data,
columns,
state: { sorting },
onSortingChange: setSorting,
getCoreRowModel: getCoreRowModel(),
getSortedRowModel: getSortedRowModel(),
});
// In column def:
columnHelper.accessor("createdAt", {
header: "Created",
sortingFn: "datetime", // Required for Date objects
});Gotcha: Dates don't sort correctly with default sort. Use for Date columns.
sortingFn: "datetime"通过 和受控状态启用排序。详细内容请参考 examples/sorting.md。
getSortedRowModeltypescript
const [sorting, setSorting] = useState<SortingState>([]);
const table = useReactTable({
data,
columns,
state: { sorting },
onSortingChange: setSorting,
getCoreRowModel: getCoreRowModel(),
getSortedRowModel: getSortedRowModel(),
});
// 在列定义中:
columnHelper.accessor("createdAt", {
header: "Created",
sortingFn: "datetime", // 处理Date对象时必填
});注意事项: 默认排序对日期处理不正确,日期列需使用 。
sortingFn: "datetime"Pattern 3: Filtering
模式3:筛选
Column filters and global filter with . See examples/filtering.md.
getFilteredRowModeltypescript
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
const [globalFilter, setGlobalFilter] = useState("");
const table = useReactTable({
data,
columns,
state: { columnFilters, globalFilter },
onColumnFiltersChange: setColumnFilters,
onGlobalFilterChange: setGlobalFilter,
getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(),
});Gotcha: Multiple column filters combine with AND logic, not OR. Use global filter or custom logic for OR behavior.
通过 实现列筛选和全局筛选。详细内容请参考 examples/filtering.md。
getFilteredRowModeltypescript
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
const [globalFilter, setGlobalFilter] = useState("");
const table = useReactTable({
data,
columns,
state: { columnFilters, globalFilter },
onColumnFiltersChange: setColumnFilters,
onGlobalFilterChange: setGlobalFilter,
getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(),
});注意事项: 多列筛选默认是AND逻辑,而非OR逻辑。如需OR逻辑,请使用全局筛选或自定义逻辑。
Pattern 4: Pagination
模式4:分页
Client-side and server-side pagination with . See examples/pagination.md.
getPaginationRowModeltypescript
const DEFAULT_PAGE_SIZE = 10;
const [pagination, setPagination] = useState<PaginationState>({
pageIndex: 0,
pageSize: DEFAULT_PAGE_SIZE,
});
const table = useReactTable({
data,
columns,
state: { pagination },
onPaginationChange: setPagination,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
});Gotcha: is 0-based internally, but many APIs are 1-based. Add 1 when sending to server.
pageIndex通过 实现客户端和服务端分页。详细内容请参考 examples/pagination.md。
getPaginationRowModeltypescript
const DEFAULT_PAGE_SIZE = 10;
const [pagination, setPagination] = useState<PaginationState>({
pageIndex: 0,
pageSize: DEFAULT_PAGE_SIZE,
});
const table = useReactTable({
data,
columns,
state: { pagination },
onPaginationChange: setPagination,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
});注意事项: 内部是0起始,但很多API是1起始,发送到服务端时需加1。
pageIndexPattern 5: Row Selection
模式5:行选择
Single and multi-row selection. See examples/selection.md.
typescript
const [rowSelection, setRowSelection] = useState<RowSelectionState>({});
const table = useReactTable({
data,
columns,
state: { rowSelection },
onRowSelectionChange: setRowSelection,
getCoreRowModel: getCoreRowModel(),
enableRowSelection: true,
getRowId: (row) => row.id, // CRITICAL: Stable IDs for selection
});Critical: Without , selection uses array indices which break when data is re-ordered or filtered.
getRowId实现单行和多行选择。详细内容请参考 examples/selection.md。
typescript
const [rowSelection, setRowSelection] = useState<RowSelectionState>({});
const table = useReactTable({
data,
columns,
state: { rowSelection },
onRowSelectionChange: setRowSelection,
getCoreRowModel: getCoreRowModel(),
enableRowSelection: true,
getRowId: (row) => row.id, // 重要提示:选择功能需要稳定的ID
});重要提示: 如果不设置 ,选择功能会使用数组索引,当数据重新排序或筛选时会失效。
getRowIdPattern 6: Server-Side Data
模式6:服务端数据
Handle server-side pagination, sorting, and filtering. See examples/server-side.md.
typescript
const table = useReactTable({
data: apiData ?? [],
columns,
state: { pagination, sorting, columnFilters },
onPaginationChange: setPagination,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
getCoreRowModel: getCoreRowModel(),
// CRITICAL: All three manual flags for server-side
manualPagination: true,
manualSorting: true,
manualFiltering: true,
rowCount: totalFromApi,
});Critical: Do NOT import client-side row models (, etc.) with - they are redundant.
getSortedRowModelmanual*: true处理服务端分页、排序和筛选。详细内容请参考 examples/server-side.md。
typescript
const table = useReactTable({
data: apiData ?? [],
columns,
state: { pagination, sorting, columnFilters },
onPaginationChange: setPagination,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
getCoreRowModel: getCoreRowModel(),
// 重要提示:服务端处理时必须设置这三个手动标记
manualPagination: true,
manualSorting: true,
manualFiltering: true,
rowCount: totalFromApi,
});重要提示: 当设置 时,不要导入客户端行模型(如 等)——它们是冗余的。
manual*: truegetSortedRowModelPattern 7: Column Visibility
模式7:列可见性
Toggle column visibility. See examples/column-visibility.md.
typescript
const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({
email: false, // Hide by default
});
// In column def - prevent hiding required columns:
columnHelper.accessor("id", { enableHiding: false });切换列的可见性。详细内容请参考 examples/column-visibility.md。
typescript
const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({
email: false, // 默认隐藏
});
// 在列定义中 - 禁止隐藏必填列:
columnHelper.accessor("id", { enableHiding: false });Pattern 8: Expanding Rows
模式8:行展开
Expandable rows for hierarchical data or detail views. See examples/expanding.md.
typescript
const [expanded, setExpanded] = useState<ExpandedState>({});
const table = useReactTable({
data,
columns,
state: { expanded },
onExpandedChange: setExpanded,
getCoreRowModel: getCoreRowModel(),
getExpandedRowModel: getExpandedRowModel(),
getRowCanExpand: () => true,
});为层级数据或详情视图实现可展开行。详细内容请参考 examples/expanding.md。
typescript
const [expanded, setExpanded] = useState<ExpandedState>({});
const table = useReactTable({
data,
columns,
state: { expanded },
onExpandedChange: setExpanded,
getCoreRowModel: getCoreRowModel(),
getExpandedRowModel: getExpandedRowModel(),
getRowCanExpand: () => true,
});Pattern 9: Reusable Generic Table Component
模式9:可复用泛型表格组件
Leverage TypeScript generics for a reusable table component. See examples/core.md.
typescript
interface DataTableProps<TData, TValue> {
columns: ColumnDef<TData, TValue>[];
data: TData[];
}
export function DataTable<TData, TValue>({
columns,
data,
}: DataTableProps<TData, TValue>) {
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
});
// ... render table
}利用TypeScript泛型实现可复用表格组件。详细内容请参考 examples/core.md。
typescript
interface DataTableProps<TData, TValue> {
columns: ColumnDef<TData, TValue>[];
data: TData[];
}
export function DataTable<TData, TValue>({
columns,
data,
}: DataTableProps<TData, TValue>) {
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
});
// ... 渲染表格
}Pattern 10: Column Pinning
模式10:列固定
Keep columns visible during horizontal scroll. See examples/column-pinning.md.
typescript
const [columnPinning, setColumnPinning] = useState<ColumnPinningState>({
left: ["id"],
right: ["actions"],
});Critical: Pinning provides state only. You must apply and background CSS yourself to prevent content overlap.
position: sticky在水平滚动时保持列可见。详细内容请参考 examples/column-pinning.md。
typescript
const [columnPinning, setColumnPinning] = useState<ColumnPinningState>({
left: ["id"],
right: ["actions"],
});重要提示: 固定仅提供状态,你需要自己设置 和背景CSS来防止内容重叠。
position: stickyPattern 11: Column Resizing
模式11:列宽调整
User-adjustable column widths. See examples/column-resizing.md.
typescript
const table = useReactTable({
data,
columns,
columnResizeMode: "onChange", // or "onEnd" for simpler, more performant
enableColumnResizing: true,
});Critical: requires CSS variables pattern and memoized table body for 60fps performance. Use for simpler cases.
</patterns>
columnResizeMode: "onChange""onEnd"<red_flags>
支持用户调整列宽。详细内容请参考 examples/column-resizing.md。
typescript
const table = useReactTable({
data,
columns,
columnResizeMode: "onChange", // 或使用 "onEnd" 实现更简单、高性能的调整
enableColumnResizing: true,
});重要提示: 需要CSS变量模式和记忆化的表格主体才能达到60fps的性能。简单场景建议使用 。
</patterns>
columnResizeMode: "onChange""onEnd"<red_flags>
RED FLAGS
注意事项
High Priority Issues:
- Missing useMemo on columns/data - Columns or data defined inline without memoization cause infinite re-renders. Must be memoized or defined outside the component.
- accessorFn without id - Using without providing an
accessorFncauses runtime errors.id - Missing manualPagination for server-side - Forgetting when using server-side data causes the table to paginate already-paginated data.
manualPagination: true - Returning JSX from accessorFn - Accessors return primitive values for sorting/filtering. Use the option for JSX rendering.
cell
Medium Priority Issues:
- Not providing rowCount for server-side - Without or
rowCount, the table cannot calculate correct page count.pageCount - Missing getRowId with selection - Without , row selection uses array indices which break on sort/filter.
getRowId - Not using flexRender - Manually rendering header/cell values breaks when columnDef uses a function for header/cell.
Gotchas & Edge Cases:
- Date sorting requires - JavaScript dates don't sort correctly by default
sortingFn: "datetime" - Column filters are AND, not OR - Multiple column filters combine with AND logic
- is 0-based - Many APIs use 1-based; add 1 when sending to server
pageIndex - defaults to
autoResetPageIndex- Page resets to 0 when data changes; set totruefor server-sidefalse - Column pinning requires sticky CSS - TanStack Table provides state only, you apply CSS
- needs CSS variables + memoized body for performance
columnResizeMode: "onChange" - Attach to both
getResizeHandlerandonMouseDownfor mobile supportonTouchStart - Pinning affects column order - Pinning, column ordering, and grouping all reorder columns; pinning happens first
- Pinned cells need background color - Otherwise scrolling content shows through
</red_flags>
<critical_reminders>
高优先级问题:
- 未对列/数据使用useMemo - 内联定义列或数据而不进行记忆化会导致无限重渲染,必须进行记忆化或在组件外部定义
- accessorFn未设置id - 使用 但未提供
accessorFn会导致运行时错误id - 服务端处理未设置manualPagination - 处理服务端数据时忘记设置 会导致表格对已分页的数据再次分页
manualPagination: true - accessorFn返回JSX - 访问器应返回原始值用于排序/筛选,如需渲染JSX请使用 选项
cell
中优先级问题:
- 服务端处理未提供rowCount - 没有 或
rowCount,表格无法计算正确的页数pageCount - 选择功能未设置getRowId - 没有 ,行选择会使用数组索引,在排序/筛选时会失效
getRowId - 未使用flexRender - 手动渲染表头/单元格值会破坏列定义中使用函数的表头/单元格逻辑
注意事项与边缘情况:
- 日期排序需要 - JavaScript日期默认排序不正确
sortingFn: "datetime" - 列筛选是AND逻辑,而非OR逻辑 - 多列筛选默认是AND组合
- 是0起始 - 很多API使用1起始,发送到服务端时需加1
pageIndex - 默认是
autoResetPageIndex- 数据变化时页面会重置为0,服务端处理时需设置为truefalse - 列固定需要sticky CSS - TanStack Table仅提供状态,需自行应用CSS
- 需要CSS变量+记忆化主体才能保证性能
columnResizeMode: "onChange" - 移动端支持需将 同时绑定到
getResizeHandler和onMouseDownonTouchStart - 列固定会影响列顺序 - 固定、列排序和分组都会改变列顺序,固定操作优先级最高
- 固定单元格需要背景色 - 否则滚动内容会透显
</red_flags>
<critical_reminders>
CRITICAL REMINDERS
重要提醒
All code must follow project conventions in CLAUDE.md
(You MUST memoize data and columns with - unstable references cause infinite re-renders)
useMemo(You MUST use for type-safe column definitions with proper TValue inference)
createColumnHelper<TData>()(You MUST import row models explicitly - , , etc. - for tree-shaking)
getSortedRowModelgetFilteredRowModel(You MUST use for direct property access and with explicit for computed values)
accessorKeyaccessorFnid(You MUST set , , to for server-side data)
manualPaginationmanualSortingmanualFilteringtrueFailure to follow these rules will cause infinite re-renders, TypeScript errors, and incorrect server-side behavior.
</critical_reminders>
所有代码必须遵循 CLAUDE.md 中的项目规范
(必须使用 对数据和列进行记忆化处理——不稳定的引用会导致无限重渲染)
useMemo(必须使用 实现类型安全的列定义,并确保正确的 TValue 类型推断)
createColumnHelper<TData>()(必须显式导入行模型——如 、 等——以支持摇树优化)
getSortedRowModelgetFilteredRowModel(直接属性访问必须使用 ,计算值必须使用带显式 的 )
accessorKeyidaccessorFn(处理服务端数据时,必须将 、、 设置为 )
manualPaginationmanualSortingmanualFilteringtrue不遵循这些规则会导致无限重渲染、TypeScript错误和服务端行为异常。
</critical_reminders>