@tanstack/table-core 9.0.0-alpha.47 → 9.0.0-alpha.48
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -0
- package/dist/core/cells/coreCellsFeature.utils.cjs +11 -8
- package/dist/core/cells/coreCellsFeature.utils.cjs.map +1 -1
- package/dist/core/cells/coreCellsFeature.utils.d.cts +11 -8
- package/dist/core/cells/coreCellsFeature.utils.d.ts +11 -8
- package/dist/core/cells/coreCellsFeature.utils.js +11 -8
- package/dist/core/cells/coreCellsFeature.utils.js.map +1 -1
- package/dist/core/columns/coreColumnsFeature.types.d.cts +7 -6
- package/dist/core/columns/coreColumnsFeature.types.d.ts +7 -6
- package/dist/core/columns/coreColumnsFeature.utils.cjs +37 -27
- package/dist/core/columns/coreColumnsFeature.utils.cjs.map +1 -1
- package/dist/core/columns/coreColumnsFeature.utils.d.cts +37 -27
- package/dist/core/columns/coreColumnsFeature.utils.d.ts +37 -27
- package/dist/core/columns/coreColumnsFeature.utils.js +37 -27
- package/dist/core/columns/coreColumnsFeature.utils.js.map +1 -1
- package/dist/core/headers/coreHeadersFeature.types.d.cts +6 -4
- package/dist/core/headers/coreHeadersFeature.types.d.ts +6 -4
- package/dist/core/headers/coreHeadersFeature.utils.cjs +23 -18
- package/dist/core/headers/coreHeadersFeature.utils.cjs.map +1 -1
- package/dist/core/headers/coreHeadersFeature.utils.d.cts +23 -18
- package/dist/core/headers/coreHeadersFeature.utils.d.ts +23 -18
- package/dist/core/headers/coreHeadersFeature.utils.js +23 -18
- package/dist/core/headers/coreHeadersFeature.utils.js.map +1 -1
- package/dist/core/row-models/coreRowModelsFeature.utils.cjs +48 -36
- package/dist/core/row-models/coreRowModelsFeature.utils.cjs.map +1 -1
- package/dist/core/row-models/coreRowModelsFeature.utils.d.cts +48 -36
- package/dist/core/row-models/coreRowModelsFeature.utils.d.ts +48 -36
- package/dist/core/row-models/coreRowModelsFeature.utils.js +48 -36
- package/dist/core/row-models/coreRowModelsFeature.utils.js.map +1 -1
- package/dist/core/rows/coreRowsFeature.types.d.cts +4 -4
- package/dist/core/rows/coreRowsFeature.types.d.ts +4 -4
- package/dist/core/rows/coreRowsFeature.utils.cjs +34 -28
- package/dist/core/rows/coreRowsFeature.utils.cjs.map +1 -1
- package/dist/core/rows/coreRowsFeature.utils.d.cts +34 -28
- package/dist/core/rows/coreRowsFeature.utils.d.ts +34 -28
- package/dist/core/rows/coreRowsFeature.utils.js +34 -28
- package/dist/core/rows/coreRowsFeature.utils.js.map +1 -1
- package/dist/core/table/coreTablesFeature.types.d.cts +6 -2
- package/dist/core/table/coreTablesFeature.types.d.ts +6 -2
- package/dist/core/table/coreTablesFeature.utils.cjs +2 -2
- package/dist/core/table/coreTablesFeature.utils.cjs.map +1 -1
- package/dist/core/table/coreTablesFeature.utils.d.cts +2 -2
- package/dist/core/table/coreTablesFeature.utils.d.ts +2 -2
- package/dist/core/table/coreTablesFeature.utils.js +2 -2
- package/dist/core/table/coreTablesFeature.utils.js.map +1 -1
- package/dist/features/column-faceting/columnFacetingFeature.types.d.cts +16 -10
- package/dist/features/column-faceting/columnFacetingFeature.types.d.ts +16 -10
- package/dist/features/column-faceting/columnFacetingFeature.utils.cjs +26 -18
- package/dist/features/column-faceting/columnFacetingFeature.utils.cjs.map +1 -1
- package/dist/features/column-faceting/columnFacetingFeature.utils.d.cts +26 -18
- package/dist/features/column-faceting/columnFacetingFeature.utils.d.ts +26 -18
- package/dist/features/column-faceting/columnFacetingFeature.utils.js +26 -18
- package/dist/features/column-faceting/columnFacetingFeature.utils.js.map +1 -1
- package/dist/features/column-filtering/columnFilteringFeature.types.d.cts +21 -11
- package/dist/features/column-filtering/columnFilteringFeature.types.d.ts +21 -11
- package/dist/features/column-filtering/columnFilteringFeature.utils.cjs +39 -28
- package/dist/features/column-filtering/columnFilteringFeature.utils.cjs.map +1 -1
- package/dist/features/column-filtering/columnFilteringFeature.utils.d.cts +39 -28
- package/dist/features/column-filtering/columnFilteringFeature.utils.d.ts +39 -28
- package/dist/features/column-filtering/columnFilteringFeature.utils.js +39 -28
- package/dist/features/column-filtering/columnFilteringFeature.utils.js.map +1 -1
- package/dist/features/column-grouping/columnGroupingFeature.types.d.cts +18 -14
- package/dist/features/column-grouping/columnGroupingFeature.types.d.ts +18 -14
- package/dist/features/column-grouping/columnGroupingFeature.utils.cjs +55 -43
- package/dist/features/column-grouping/columnGroupingFeature.utils.cjs.map +1 -1
- package/dist/features/column-grouping/columnGroupingFeature.utils.d.cts +55 -43
- package/dist/features/column-grouping/columnGroupingFeature.utils.d.ts +55 -43
- package/dist/features/column-grouping/columnGroupingFeature.utils.js +55 -43
- package/dist/features/column-grouping/columnGroupingFeature.utils.js.map +1 -1
- package/dist/features/column-ordering/columnOrderingFeature.types.d.cts +14 -5
- package/dist/features/column-ordering/columnOrderingFeature.types.d.ts +14 -5
- package/dist/features/column-ordering/columnOrderingFeature.utils.cjs +30 -23
- package/dist/features/column-ordering/columnOrderingFeature.utils.cjs.map +1 -1
- package/dist/features/column-ordering/columnOrderingFeature.utils.d.cts +30 -23
- package/dist/features/column-ordering/columnOrderingFeature.utils.d.ts +30 -23
- package/dist/features/column-ordering/columnOrderingFeature.utils.js +30 -23
- package/dist/features/column-ordering/columnOrderingFeature.utils.js.map +1 -1
- package/dist/features/column-pinning/columnPinningFeature.types.d.cts +43 -31
- package/dist/features/column-pinning/columnPinningFeature.types.d.ts +43 -31
- package/dist/features/column-pinning/columnPinningFeature.utils.cjs +111 -91
- package/dist/features/column-pinning/columnPinningFeature.utils.cjs.map +1 -1
- package/dist/features/column-pinning/columnPinningFeature.utils.d.cts +111 -91
- package/dist/features/column-pinning/columnPinningFeature.utils.d.ts +111 -91
- package/dist/features/column-pinning/columnPinningFeature.utils.js +111 -91
- package/dist/features/column-pinning/columnPinningFeature.utils.js.map +1 -1
- package/dist/features/column-resizing/columnResizingFeature.types.d.cts +9 -9
- package/dist/features/column-resizing/columnResizingFeature.types.d.ts +9 -9
- package/dist/features/column-resizing/columnResizingFeature.utils.cjs +28 -19
- package/dist/features/column-resizing/columnResizingFeature.utils.cjs.map +1 -1
- package/dist/features/column-resizing/columnResizingFeature.utils.d.cts +28 -19
- package/dist/features/column-resizing/columnResizingFeature.utils.d.ts +28 -19
- package/dist/features/column-resizing/columnResizingFeature.utils.js +28 -19
- package/dist/features/column-resizing/columnResizingFeature.utils.js.map +1 -1
- package/dist/features/column-sizing/columnSizingFeature.types.d.cts +19 -12
- package/dist/features/column-sizing/columnSizingFeature.types.d.ts +19 -12
- package/dist/features/column-sizing/columnSizingFeature.utils.cjs +52 -41
- package/dist/features/column-sizing/columnSizingFeature.utils.cjs.map +1 -1
- package/dist/features/column-sizing/columnSizingFeature.utils.d.cts +52 -41
- package/dist/features/column-sizing/columnSizingFeature.utils.d.ts +52 -41
- package/dist/features/column-sizing/columnSizingFeature.utils.js +52 -41
- package/dist/features/column-sizing/columnSizingFeature.utils.js.map +1 -1
- package/dist/features/column-visibility/columnVisibilityFeature.types.d.cts +16 -13
- package/dist/features/column-visibility/columnVisibilityFeature.types.d.ts +16 -13
- package/dist/features/column-visibility/columnVisibilityFeature.utils.cjs +54 -42
- package/dist/features/column-visibility/columnVisibilityFeature.utils.cjs.map +1 -1
- package/dist/features/column-visibility/columnVisibilityFeature.utils.d.cts +54 -42
- package/dist/features/column-visibility/columnVisibilityFeature.utils.d.ts +54 -42
- package/dist/features/column-visibility/columnVisibilityFeature.utils.js +54 -42
- package/dist/features/column-visibility/columnVisibilityFeature.utils.js.map +1 -1
- package/dist/features/global-filtering/globalFilteringFeature.types.d.cts +10 -5
- package/dist/features/global-filtering/globalFilteringFeature.types.d.ts +10 -5
- package/dist/features/global-filtering/globalFilteringFeature.utils.cjs +20 -14
- package/dist/features/global-filtering/globalFilteringFeature.utils.cjs.map +1 -1
- package/dist/features/global-filtering/globalFilteringFeature.utils.d.cts +20 -14
- package/dist/features/global-filtering/globalFilteringFeature.utils.d.ts +20 -14
- package/dist/features/global-filtering/globalFilteringFeature.utils.js +20 -14
- package/dist/features/global-filtering/globalFilteringFeature.utils.js.map +1 -1
- package/dist/features/row-expanding/rowExpandingFeature.types.d.cts +16 -15
- package/dist/features/row-expanding/rowExpandingFeature.types.d.ts +16 -15
- package/dist/features/row-expanding/rowExpandingFeature.utils.cjs +56 -41
- package/dist/features/row-expanding/rowExpandingFeature.utils.cjs.map +1 -1
- package/dist/features/row-expanding/rowExpandingFeature.utils.d.cts +56 -41
- package/dist/features/row-expanding/rowExpandingFeature.utils.d.ts +56 -41
- package/dist/features/row-expanding/rowExpandingFeature.utils.js +56 -41
- package/dist/features/row-expanding/rowExpandingFeature.utils.js.map +1 -1
- package/dist/features/row-pagination/rowPaginationFeature.types.d.cts +19 -12
- package/dist/features/row-pagination/rowPaginationFeature.types.d.ts +19 -12
- package/dist/features/row-pagination/rowPaginationFeature.utils.cjs +49 -32
- package/dist/features/row-pagination/rowPaginationFeature.utils.cjs.map +1 -1
- package/dist/features/row-pagination/rowPaginationFeature.utils.d.cts +49 -32
- package/dist/features/row-pagination/rowPaginationFeature.utils.d.ts +49 -32
- package/dist/features/row-pagination/rowPaginationFeature.utils.js +49 -32
- package/dist/features/row-pagination/rowPaginationFeature.utils.js.map +1 -1
- package/dist/features/row-pinning/rowPinningFeature.types.d.cts +12 -8
- package/dist/features/row-pinning/rowPinningFeature.types.d.ts +12 -8
- package/dist/features/row-pinning/rowPinningFeature.utils.cjs +39 -29
- package/dist/features/row-pinning/rowPinningFeature.utils.cjs.map +1 -1
- package/dist/features/row-pinning/rowPinningFeature.utils.d.cts +39 -29
- package/dist/features/row-pinning/rowPinningFeature.utils.d.ts +39 -29
- package/dist/features/row-pinning/rowPinningFeature.utils.js +39 -29
- package/dist/features/row-pinning/rowPinningFeature.utils.js.map +1 -1
- package/dist/features/row-selection/rowSelectionFeature.types.d.cts +30 -24
- package/dist/features/row-selection/rowSelectionFeature.types.d.ts +30 -24
- package/dist/features/row-selection/rowSelectionFeature.utils.cjs +89 -69
- package/dist/features/row-selection/rowSelectionFeature.utils.cjs.map +1 -1
- package/dist/features/row-selection/rowSelectionFeature.utils.d.cts +89 -69
- package/dist/features/row-selection/rowSelectionFeature.utils.d.ts +89 -69
- package/dist/features/row-selection/rowSelectionFeature.utils.js +89 -69
- package/dist/features/row-selection/rowSelectionFeature.utils.js.map +1 -1
- package/dist/features/row-sorting/rowSortingFeature.types.d.cts +10 -8
- package/dist/features/row-sorting/rowSortingFeature.types.d.ts +10 -8
- package/dist/features/row-sorting/rowSortingFeature.utils.cjs +61 -44
- package/dist/features/row-sorting/rowSortingFeature.utils.cjs.map +1 -1
- package/dist/features/row-sorting/rowSortingFeature.utils.d.cts +61 -44
- package/dist/features/row-sorting/rowSortingFeature.utils.d.ts +61 -44
- package/dist/features/row-sorting/rowSortingFeature.utils.js +61 -44
- package/dist/features/row-sorting/rowSortingFeature.utils.js.map +1 -1
- package/dist/fns/aggregationFns.cjs +33 -9
- package/dist/fns/aggregationFns.cjs.map +1 -1
- package/dist/fns/aggregationFns.d.cts +33 -9
- package/dist/fns/aggregationFns.d.ts +33 -9
- package/dist/fns/aggregationFns.js +33 -9
- package/dist/fns/aggregationFns.js.map +1 -1
- package/dist/fns/filterFns.cjs +48 -17
- package/dist/fns/filterFns.cjs.map +1 -1
- package/dist/fns/filterFns.d.cts +42 -15
- package/dist/fns/filterFns.d.ts +42 -15
- package/dist/fns/filterFns.js +48 -17
- package/dist/fns/filterFns.js.map +1 -1
- package/dist/helpers/columnHelper.cjs +9 -4
- package/dist/helpers/columnHelper.cjs.map +1 -1
- package/dist/helpers/columnHelper.d.cts +9 -4
- package/dist/helpers/columnHelper.d.ts +9 -4
- package/dist/helpers/columnHelper.js +9 -4
- package/dist/helpers/columnHelper.js.map +1 -1
- package/dist/helpers/tableOptions.cjs.map +1 -1
- package/dist/helpers/tableOptions.d.cts +12 -9
- package/dist/helpers/tableOptions.d.ts +12 -9
- package/dist/helpers/tableOptions.js.map +1 -1
- package/dist/types/ColumnDef.d.cts +38 -0
- package/dist/types/ColumnDef.d.ts +38 -0
- package/dist/types/TableOptions.d.cts +15 -0
- package/dist/types/TableOptions.d.ts +15 -0
- package/dist/types/TableState.d.cts +12 -0
- package/dist/types/TableState.d.ts +12 -0
- package/package.json +5 -3
- package/skills/column-definitions/SKILL.md +333 -0
- package/skills/column-layout/SKILL.md +328 -0
- package/skills/column-layout/references/subsystems.md +220 -0
- package/skills/customizing-feature-behavior/SKILL.md +416 -0
- package/skills/filtering/SKILL.md +357 -0
- package/skills/filtering/references/faceting-and-fuzzy.md +191 -0
- package/skills/grouping/SKILL.md +448 -0
- package/skills/migrate-v8-to-v9/SKILL.md +495 -0
- package/skills/pagination/SKILL.md +385 -0
- package/skills/row-expanding/SKILL.md +348 -0
- package/skills/row-pinning/SKILL.md +269 -0
- package/skills/row-selection/SKILL.md +391 -0
- package/skills/setup/SKILL.md +400 -0
- package/skills/sorting/SKILL.md +344 -0
- package/skills/state-management/SKILL.md +388 -0
- package/src/core/cells/coreCellsFeature.utils.ts +11 -8
- package/src/core/columns/coreColumnsFeature.types.ts +7 -6
- package/src/core/columns/coreColumnsFeature.utils.ts +37 -27
- package/src/core/headers/coreHeadersFeature.types.ts +6 -4
- package/src/core/headers/coreHeadersFeature.utils.ts +23 -18
- package/src/core/row-models/coreRowModelsFeature.utils.ts +48 -36
- package/src/core/rows/coreRowsFeature.types.ts +4 -4
- package/src/core/rows/coreRowsFeature.utils.ts +34 -28
- package/src/core/table/coreTablesFeature.types.ts +6 -2
- package/src/core/table/coreTablesFeature.utils.ts +2 -2
- package/src/features/column-faceting/columnFacetingFeature.types.ts +16 -10
- package/src/features/column-faceting/columnFacetingFeature.utils.ts +26 -18
- package/src/features/column-filtering/columnFilteringFeature.types.ts +21 -11
- package/src/features/column-filtering/columnFilteringFeature.utils.ts +39 -28
- package/src/features/column-grouping/columnGroupingFeature.types.ts +18 -14
- package/src/features/column-grouping/columnGroupingFeature.utils.ts +55 -43
- package/src/features/column-ordering/columnOrderingFeature.types.ts +14 -5
- package/src/features/column-ordering/columnOrderingFeature.utils.ts +30 -23
- package/src/features/column-pinning/columnPinningFeature.types.ts +43 -31
- package/src/features/column-pinning/columnPinningFeature.utils.ts +111 -91
- package/src/features/column-resizing/columnResizingFeature.types.ts +9 -9
- package/src/features/column-resizing/columnResizingFeature.utils.ts +28 -19
- package/src/features/column-sizing/columnSizingFeature.types.ts +19 -12
- package/src/features/column-sizing/columnSizingFeature.utils.ts +52 -41
- package/src/features/column-visibility/columnVisibilityFeature.types.ts +16 -13
- package/src/features/column-visibility/columnVisibilityFeature.utils.ts +54 -42
- package/src/features/global-filtering/globalFilteringFeature.types.ts +10 -5
- package/src/features/global-filtering/globalFilteringFeature.utils.ts +20 -14
- package/src/features/row-expanding/rowExpandingFeature.types.ts +16 -15
- package/src/features/row-expanding/rowExpandingFeature.utils.ts +56 -41
- package/src/features/row-pagination/rowPaginationFeature.types.ts +19 -12
- package/src/features/row-pagination/rowPaginationFeature.utils.ts +49 -32
- package/src/features/row-pinning/rowPinningFeature.types.ts +12 -8
- package/src/features/row-pinning/rowPinningFeature.utils.ts +39 -29
- package/src/features/row-selection/rowSelectionFeature.types.ts +30 -24
- package/src/features/row-selection/rowSelectionFeature.utils.ts +89 -69
- package/src/features/row-sorting/rowSortingFeature.types.ts +10 -8
- package/src/features/row-sorting/rowSortingFeature.utils.ts +61 -44
- package/src/fns/aggregationFns.ts +33 -9
- package/src/fns/filterFns.ts +48 -17
- package/src/helpers/columnHelper.ts +9 -4
- package/src/helpers/tableOptions.ts +12 -9
- package/src/types/ColumnDef.ts +38 -0
- package/src/types/TableOptions.ts +15 -0
- package/src/types/TableState.ts +12 -0
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: column-definitions
|
|
3
|
+
description: >
|
|
4
|
+
Define TanStack Table v9 columns with `createColumnHelper<typeof _features, TData>()`.
|
|
5
|
+
Covers `columnHelper.accessor` (key + function forms), `columnHelper.display`,
|
|
6
|
+
`columnHelper.group`, `columnHelper.columns`, the `ColumnDef`/`AccessorKeyColumnDef`/
|
|
7
|
+
`AccessorFnColumnDef`/`DisplayColumnDef`/`GroupColumnDef` types, `accessorKey` with
|
|
8
|
+
`DeepKeys`, `accessorFn`, the `header`/`cell`/`footer`/`aggregatedCell` renderers,
|
|
9
|
+
required `id` rules, and `getRowId` for stable row identity.
|
|
10
|
+
type: core
|
|
11
|
+
library: tanstack-table
|
|
12
|
+
library_version: '9.0.0-alpha.47'
|
|
13
|
+
sources:
|
|
14
|
+
- TanStack/table:docs/guide/column-defs.md
|
|
15
|
+
- TanStack/table:docs/guide/columns.md
|
|
16
|
+
- TanStack/table:packages/table-core/src/helpers/columnHelper.ts
|
|
17
|
+
- TanStack/table:packages/table-core/src/core/columns/constructColumn.ts
|
|
18
|
+
- TanStack/table:examples/react/basic-use-table/src/main.tsx
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Setup
|
|
22
|
+
|
|
23
|
+
`createColumnHelper` takes TWO generics in v9: the features type (so accessor keys, sort/filter strings, etc. are typed against your registered features) and the row data type.
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import {
|
|
27
|
+
createColumnHelper,
|
|
28
|
+
tableFeatures,
|
|
29
|
+
rowSortingFeature,
|
|
30
|
+
} from '@tanstack/table-core'
|
|
31
|
+
|
|
32
|
+
type Person = {
|
|
33
|
+
id: string
|
|
34
|
+
firstName: string
|
|
35
|
+
lastName: string
|
|
36
|
+
age: number
|
|
37
|
+
visits: number
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const _features = tableFeatures({ rowSortingFeature })
|
|
41
|
+
|
|
42
|
+
// TFeatures FIRST, TData SECOND
|
|
43
|
+
const columnHelper = createColumnHelper<typeof _features, Person>()
|
|
44
|
+
|
|
45
|
+
const columns = columnHelper.columns([
|
|
46
|
+
// accessorKey — deep keys via DeepKeys (dot paths) are supported
|
|
47
|
+
columnHelper.accessor('firstName', { header: 'First Name' }),
|
|
48
|
+
columnHelper.accessor('lastName', { header: 'Last Name' }),
|
|
49
|
+
columnHelper.accessor('age', { header: 'Age' }),
|
|
50
|
+
|
|
51
|
+
// accessorFn — needs an explicit `id`
|
|
52
|
+
columnHelper.accessor((row) => `${row.firstName} ${row.lastName}`, {
|
|
53
|
+
id: 'fullName',
|
|
54
|
+
header: 'Full Name',
|
|
55
|
+
cell: (info) => info.getValue(),
|
|
56
|
+
}),
|
|
57
|
+
|
|
58
|
+
// display column — no value extraction, just rendering
|
|
59
|
+
columnHelper.display({
|
|
60
|
+
id: 'actions',
|
|
61
|
+
header: 'Actions',
|
|
62
|
+
cell: ({ row }) => `Edit ${row.original.id}`,
|
|
63
|
+
}),
|
|
64
|
+
|
|
65
|
+
// group column — wraps child columns under a shared header
|
|
66
|
+
columnHelper.group({
|
|
67
|
+
id: 'stats',
|
|
68
|
+
header: 'Stats',
|
|
69
|
+
columns: [columnHelper.accessor('visits', { header: 'Visits' })],
|
|
70
|
+
}),
|
|
71
|
+
])
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Core Patterns
|
|
75
|
+
|
|
76
|
+
### Stable row identity with `getRowId`
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
const table = useTable({
|
|
80
|
+
_features,
|
|
81
|
+
_rowModels: {},
|
|
82
|
+
columns,
|
|
83
|
+
data,
|
|
84
|
+
getRowId: (row) => row.id, // ← stable from row's own data
|
|
85
|
+
})
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Without `getRowId`, `row.id` defaults to the row's array index. Row-keyed state (selection, expansion, pinning) then attaches to whatever happens to be at that index after a sort/filter/refetch.
|
|
89
|
+
|
|
90
|
+
### Accessor key with deep path
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
type User = { name: { first: string; last: string } }
|
|
94
|
+
|
|
95
|
+
const columnHelper = createColumnHelper<typeof _features, User>()
|
|
96
|
+
|
|
97
|
+
columnHelper.accessor('name.first', { header: 'First' })
|
|
98
|
+
columnHelper.accessor('name.last', { header: 'Last' })
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
For nested objects with non-optional intermediate keys, the dotted `accessorKey` form works and infers the right value type. Switch to `accessorFn` when intermediates are optional (see Common Mistakes below).
|
|
102
|
+
|
|
103
|
+
### Header / cell / footer renderers
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
columnHelper.accessor('age', {
|
|
107
|
+
header: () => 'Age',
|
|
108
|
+
cell: (info) => info.getValue(),
|
|
109
|
+
footer: (info) => `${info.table.getRowModel().rows.length} rows`,
|
|
110
|
+
})
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Renderers accept string, JSX (in framework adapters), or function forms. Render via `flexRender(def, ctx)` or `<table.FlexRender header={header} />` so all three forms work uniformly.
|
|
114
|
+
|
|
115
|
+
### `columnHelper.columns([...])` for module-scope stability
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
// Outside any component / hook — stable reference forever
|
|
119
|
+
const columns = columnHelper.columns([
|
|
120
|
+
columnHelper.accessor('firstName', { header: 'First' }),
|
|
121
|
+
columnHelper.accessor('lastName', { header: 'Last' }),
|
|
122
|
+
])
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
`columnHelper.columns` returns the array as-is but preserves the precise tuple types. Hoist to module scope or wrap in `useMemo` — the table compares `columns` by reference.
|
|
126
|
+
|
|
127
|
+
## Common Mistakes
|
|
128
|
+
|
|
129
|
+
### [CRITICAL] Passing only `TData` to `createColumnHelper`
|
|
130
|
+
|
|
131
|
+
Wrong:
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
// v8 signature — TData ends up in the TFeatures slot
|
|
135
|
+
const columnHelper = createColumnHelper<Person>()
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Correct:
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
const _features = tableFeatures({ rowSortingFeature })
|
|
142
|
+
const columnHelper = createColumnHelper<typeof _features, Person>()
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
v9 changed the generic order: `<TFeatures, TData>`. The compiler error is noisy because `Person` lands in the `TFeatures` slot and breaks every column type that follows.
|
|
146
|
+
|
|
147
|
+
Source: packages/table-core/src/helpers/columnHelper.ts; docs/framework/react/guide/migrating.md
|
|
148
|
+
|
|
149
|
+
### [HIGH] Accessor function returns an object or array
|
|
150
|
+
|
|
151
|
+
Wrong:
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
// returns an object — built-in alphanumeric sort and includesString filter break
|
|
155
|
+
columnHelper.accessor((row) => row.name, {
|
|
156
|
+
id: 'name',
|
|
157
|
+
cell: (info) => `${info.getValue().first} ${info.getValue().last}`,
|
|
158
|
+
})
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Correct:
|
|
162
|
+
|
|
163
|
+
```ts
|
|
164
|
+
// accessor returns a primitive; cell can still format it
|
|
165
|
+
columnHelper.accessor((row) => `${row.name.first} ${row.name.last}`, {
|
|
166
|
+
id: 'fullName',
|
|
167
|
+
cell: (info) => info.getValue(),
|
|
168
|
+
})
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
The accessed value drives sorting, filtering, faceting, and grouping. Built-in `sortFn`/`filterFn`/`aggregationFn` expect a primitive `string` / `number` / `Date`. Return a primitive — or supply a matching custom function.
|
|
172
|
+
|
|
173
|
+
Source: docs/guide/column-defs.md
|
|
174
|
+
|
|
175
|
+
### [CRITICAL] Omitting `id` on an `accessorFn` column
|
|
176
|
+
|
|
177
|
+
Wrong:
|
|
178
|
+
|
|
179
|
+
```tsx
|
|
180
|
+
// accessorFn + JSX header => no id can be derived
|
|
181
|
+
columnHelper.accessor((row) => row.lastName, {
|
|
182
|
+
header: () => <span>Last Name</span>,
|
|
183
|
+
cell: (info) => info.getValue(),
|
|
184
|
+
})
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Correct:
|
|
188
|
+
|
|
189
|
+
```tsx
|
|
190
|
+
columnHelper.accessor((row) => row.lastName, {
|
|
191
|
+
id: 'lastName', // required when there's no string accessorKey or string header
|
|
192
|
+
header: () => <span>Last Name</span>,
|
|
193
|
+
cell: (info) => info.getValue(),
|
|
194
|
+
})
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
The constructor throws "coreColumnsFeature require an id when using an accessorFn" in development. The same applies to non-string `header` values without a fallback `id`.
|
|
198
|
+
|
|
199
|
+
Source: packages/table-core/src/core/columns/constructColumn.ts
|
|
200
|
+
|
|
201
|
+
### [CRITICAL] Defining `columns` inside the component without `useMemo`
|
|
202
|
+
|
|
203
|
+
Wrong:
|
|
204
|
+
|
|
205
|
+
```tsx
|
|
206
|
+
function MyTable() {
|
|
207
|
+
// new array reference every render → infinite render loop
|
|
208
|
+
const columns = [
|
|
209
|
+
columnHelper.accessor('firstName', { header: 'First' }),
|
|
210
|
+
columnHelper.accessor('lastName', { header: 'Last' }),
|
|
211
|
+
]
|
|
212
|
+
const table = useTable({ _features, _rowModels: {}, columns, data })
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Correct:
|
|
217
|
+
|
|
218
|
+
```tsx
|
|
219
|
+
function MyTable() {
|
|
220
|
+
const columns = React.useMemo(
|
|
221
|
+
() =>
|
|
222
|
+
columnHelper.columns([
|
|
223
|
+
columnHelper.accessor('firstName', { header: 'First' }),
|
|
224
|
+
columnHelper.accessor('lastName', { header: 'Last' }),
|
|
225
|
+
]),
|
|
226
|
+
[],
|
|
227
|
+
)
|
|
228
|
+
const table = useTable({ _features, _rowModels: {}, columns, data })
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
TanStack Table compares `columns` and `data` by reference. The #1 FAQ entry across versions.
|
|
233
|
+
|
|
234
|
+
Source: docs/faq.md; examples/react/basic-subscribe/src/main.tsx
|
|
235
|
+
|
|
236
|
+
### [HIGH] Using array-index row IDs with mutating data
|
|
237
|
+
|
|
238
|
+
Wrong:
|
|
239
|
+
|
|
240
|
+
```ts
|
|
241
|
+
// no getRowId — rowSelection survives data updates but maps to wrong rows
|
|
242
|
+
const table = useTable({
|
|
243
|
+
_features,
|
|
244
|
+
_rowModels: {},
|
|
245
|
+
columns,
|
|
246
|
+
data,
|
|
247
|
+
enableRowSelection: true,
|
|
248
|
+
})
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Correct:
|
|
252
|
+
|
|
253
|
+
```ts
|
|
254
|
+
const table = useTable({
|
|
255
|
+
_features,
|
|
256
|
+
_rowModels: {},
|
|
257
|
+
columns,
|
|
258
|
+
data,
|
|
259
|
+
getRowId: (row) => row.id,
|
|
260
|
+
enableRowSelection: true,
|
|
261
|
+
})
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
When `data` reorders, filters, or items are removed/refetched, row-keyed state (selection, expansion, pinning) attaches to the wrong row.
|
|
265
|
+
|
|
266
|
+
Source: docs/guide/rows.md; packages/table-core/src/core/rows/coreRowsFeature.utils.ts
|
|
267
|
+
|
|
268
|
+
### [MEDIUM] `accessorKey` with optional path strips `undefined` from `getValue` type
|
|
269
|
+
|
|
270
|
+
Wrong:
|
|
271
|
+
|
|
272
|
+
```ts
|
|
273
|
+
// amount inferred as `number` even though salary is optional
|
|
274
|
+
columnHelper.accessor('user.salary.amount', {
|
|
275
|
+
cell: (info) => {
|
|
276
|
+
const amount = info.getValue() // type: number (WRONG)
|
|
277
|
+
return amount.toFixed(2) // crashes when salary is undefined
|
|
278
|
+
},
|
|
279
|
+
})
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
Correct:
|
|
283
|
+
|
|
284
|
+
```ts
|
|
285
|
+
columnHelper.accessor((row) => row.user.salary?.amount, {
|
|
286
|
+
id: 'salary',
|
|
287
|
+
cell: (info) => {
|
|
288
|
+
const amount = info.getValue() // type: number | undefined
|
|
289
|
+
return amount?.toFixed(2) ?? '-'
|
|
290
|
+
},
|
|
291
|
+
})
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
The `DeepValue` type doesn't propagate `undefined` through optional intermediates. Use `accessorFn` when any segment is optional — the type follows the expression.
|
|
295
|
+
|
|
296
|
+
Source: https://github.com/TanStack/table/issues/6238
|
|
297
|
+
|
|
298
|
+
### [MEDIUM] `columnHelper.accessor` nested inside `columnHelper.group` loses `getValue` inference
|
|
299
|
+
|
|
300
|
+
Wrong:
|
|
301
|
+
|
|
302
|
+
```ts
|
|
303
|
+
// info.getValue() inferred as unknown
|
|
304
|
+
columnHelper.group({
|
|
305
|
+
id: 'name',
|
|
306
|
+
columns: [
|
|
307
|
+
columnHelper.accessor('firstName', {
|
|
308
|
+
cell: (info) => info.getValue(), // unknown
|
|
309
|
+
}),
|
|
310
|
+
],
|
|
311
|
+
})
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
Correct:
|
|
315
|
+
|
|
316
|
+
```ts
|
|
317
|
+
// Hoist accessor definitions out of the group
|
|
318
|
+
const firstNameCol = columnHelper.accessor('firstName', {
|
|
319
|
+
cell: (info) => info.getValue(), // string
|
|
320
|
+
})
|
|
321
|
+
|
|
322
|
+
columnHelper.group({ id: 'name', columns: [firstNameCol] })
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
The group helper's overloads don't thread `TData` through correctly when accessors are defined inline.
|
|
326
|
+
|
|
327
|
+
Source: https://github.com/TanStack/table/issues/5860
|
|
328
|
+
|
|
329
|
+
## See also
|
|
330
|
+
|
|
331
|
+
- `tanstack-table/setup` — how `_features` and `_rowModels` thread through `useTable`
|
|
332
|
+
- `tanstack-table/customizing-feature-behavior` — per-column `sortFn`/`filterFn`/`aggregationFn`
|
|
333
|
+
- `tanstack-table/row-selection` — why `getRowId` is essentially mandatory
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: column-layout
|
|
3
|
+
description: >
|
|
4
|
+
The five UI-state-only column features in TanStack Table v9 that shape how
|
|
5
|
+
columns render — visibility, ordering, pinning, sizing, resizing. None
|
|
6
|
+
require a row model. Covers `columnVisibilityFeature` (getVisibleLeafColumns,
|
|
7
|
+
row.getVisibleCells), `columnOrderingFeature` (columnOrder string[], column.getIndex),
|
|
8
|
+
`columnPinningFeature` (left/right ColumnPinningState, column.pin, column.getStart /
|
|
9
|
+
getAfter, split-table getLeft*/getCenter*/getRight* APIs, sticky-CSS pattern;
|
|
10
|
+
`enableColumnPinning` table-level option distinct from per-column `enablePinning`),
|
|
11
|
+
`columnSizingFeature` (defaultColumnSizing, column.getSize, table.getTotalSize),
|
|
12
|
+
`columnResizingFeature` (columnResizeMode 'onEnd'/'onChange', columnResizeDirection
|
|
13
|
+
'ltr'/'rtl', header.getResizeHandler for mouse + touch, CSS-variable
|
|
14
|
+
performant resize pattern). Pipeline: Column Pinning → columnOrder → Grouping.
|
|
15
|
+
type: core
|
|
16
|
+
library: tanstack-table
|
|
17
|
+
library_version: '9.0.0-alpha.47'
|
|
18
|
+
requires:
|
|
19
|
+
- state-management
|
|
20
|
+
sources:
|
|
21
|
+
- TanStack/table:docs/guide/column-visibility.md
|
|
22
|
+
- TanStack/table:docs/guide/column-ordering.md
|
|
23
|
+
- TanStack/table:docs/guide/column-pinning.md
|
|
24
|
+
- TanStack/table:docs/guide/column-sizing.md
|
|
25
|
+
- TanStack/table:docs/guide/column-resizing.md
|
|
26
|
+
- TanStack/table:examples/react/column-visibility/src/main.tsx
|
|
27
|
+
- TanStack/table:examples/react/column-resizing/src/main.tsx
|
|
28
|
+
- TanStack/table:examples/react/column-resizing-performant/src/main.tsx
|
|
29
|
+
- TanStack/table:examples/react/column-pinning-split/src/main.tsx
|
|
30
|
+
- TanStack/table:examples/react/column-pinning-sticky/src/main.tsx
|
|
31
|
+
- TanStack/table:examples/react/column-dnd/src/main.tsx
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
This skill builds on `tanstack-table/state-management`. Read it first for the atom model — these are UI-state-only features (no row model).
|
|
35
|
+
|
|
36
|
+
## Setup
|
|
37
|
+
|
|
38
|
+
All five features are opt-in via `tableFeatures({...})`. The reorder pipeline is fixed: **(1) Column Pinning splits into left/center/right → (2) `columnOrder` reorders the center → (3) Grouping (`groupedColumnMode: 'reorder' | 'remove'`) may move grouped columns to the front.**
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
import {
|
|
42
|
+
tableFeatures,
|
|
43
|
+
columnVisibilityFeature,
|
|
44
|
+
columnOrderingFeature,
|
|
45
|
+
columnPinningFeature,
|
|
46
|
+
columnSizingFeature,
|
|
47
|
+
columnResizingFeature,
|
|
48
|
+
constructTable,
|
|
49
|
+
} from '@tanstack/table-core'
|
|
50
|
+
|
|
51
|
+
const _features = tableFeatures({
|
|
52
|
+
columnVisibilityFeature,
|
|
53
|
+
columnOrderingFeature,
|
|
54
|
+
columnPinningFeature,
|
|
55
|
+
columnSizingFeature,
|
|
56
|
+
columnResizingFeature, // explicit — formerly part of v8 ColumnSizing
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
const table = constructTable({
|
|
60
|
+
_features,
|
|
61
|
+
_rowModels: {}, // no row model needed for these features
|
|
62
|
+
columns,
|
|
63
|
+
data,
|
|
64
|
+
initialState: {
|
|
65
|
+
columnVisibility: {},
|
|
66
|
+
columnOrder: [],
|
|
67
|
+
columnPinning: { left: [], right: [] },
|
|
68
|
+
columnSizing: {},
|
|
69
|
+
},
|
|
70
|
+
})
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Subsystems
|
|
74
|
+
|
|
75
|
+
| Feature | State slice | Key APIs |
|
|
76
|
+
| ------------------------- | ---------------------- | ---------------------------------------------------- |
|
|
77
|
+
| `columnVisibilityFeature` | `columnVisibility` | `column.toggleVisibility()`, `row.getVisibleCells()` |
|
|
78
|
+
| `columnOrderingFeature` | `columnOrder` | `table.setColumnOrder()`, `column.getIndex()` |
|
|
79
|
+
| `columnPinningFeature` | `columnPinning` (l/r) | `column.pin()`, `column.getStart()`, `getAfter()` |
|
|
80
|
+
| `columnSizingFeature` | `columnSizing` | `column.getSize()`, `table.getTotalSize()` |
|
|
81
|
+
| `columnResizingFeature` | (transient drag state) | `header.getResizeHandler()`, `columnResizeMode` |
|
|
82
|
+
|
|
83
|
+
Full API surface, render strategies, and additional MEDIUM-priority failure modes (reorder-pinned-via-columnOrder, react-dnd/react-beautiful-dnd avoidance, touch-resize handler) in [subsystems.md](references/subsystems.md).
|
|
84
|
+
|
|
85
|
+
## Core Patterns
|
|
86
|
+
|
|
87
|
+
### Performant `'onChange'` resize (React)
|
|
88
|
+
|
|
89
|
+
```tsx
|
|
90
|
+
// From examples/react/column-resizing-performant/src/main.tsx
|
|
91
|
+
const columnSizeVars = React.useMemo(() => {
|
|
92
|
+
const headers = table.getFlatHeaders()
|
|
93
|
+
const colSizes: { [key: string]: number } = {}
|
|
94
|
+
for (const header of headers) {
|
|
95
|
+
colSizes[`--header-${header.id}-size`] = header.getSize()
|
|
96
|
+
colSizes[`--col-${header.column.id}-size`] = header.column.getSize()
|
|
97
|
+
}
|
|
98
|
+
return colSizes
|
|
99
|
+
}, [table.state.columnResizing, table.state.columnSizing])
|
|
100
|
+
|
|
101
|
+
<div className="divTable" style={{ ...columnSizeVars, width: table.getTotalSize() }}>
|
|
102
|
+
{table.store.state.columnResizing.isResizingColumn
|
|
103
|
+
? <MemoizedTableBody table={table} />
|
|
104
|
+
: <TableBody table={table} />}
|
|
105
|
+
</div>
|
|
106
|
+
|
|
107
|
+
// Body cells use the CSS variable (no per-cell getSize() call)
|
|
108
|
+
<div className="td" style={{ width: `calc(var(--col-${cell.column.id}-size) * 1px)` }}>
|
|
109
|
+
{cell.renderValue()}
|
|
110
|
+
</div>
|
|
111
|
+
|
|
112
|
+
export const MemoizedTableBody = React.memo(
|
|
113
|
+
TableBody,
|
|
114
|
+
(prev, next) => prev.table.options.data === next.table.options.data,
|
|
115
|
+
)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Common Mistakes
|
|
119
|
+
|
|
120
|
+
### [HIGH] Rendering body cells with `row.getAllCells()` while visibility is registered
|
|
121
|
+
|
|
122
|
+
Wrong:
|
|
123
|
+
|
|
124
|
+
```tsx
|
|
125
|
+
// Toggling visibility has no effect on rendered cells
|
|
126
|
+
{
|
|
127
|
+
table.getAllLeafColumns().map((column) => <th key={column.id}>...</th>)
|
|
128
|
+
}
|
|
129
|
+
{
|
|
130
|
+
row.getAllCells().map((cell) => (
|
|
131
|
+
<td key={cell.id}>
|
|
132
|
+
<table.FlexRender cell={cell} />
|
|
133
|
+
</td>
|
|
134
|
+
))
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Correct:
|
|
139
|
+
|
|
140
|
+
```tsx
|
|
141
|
+
// Header groups already respect visibility; use them for headers.
|
|
142
|
+
// For body cells, swap getAllCells → getVisibleCells.
|
|
143
|
+
<thead>
|
|
144
|
+
{table.getHeaderGroups().map((headerGroup) => (
|
|
145
|
+
<tr key={headerGroup.id}>
|
|
146
|
+
{headerGroup.headers.map((header) => (
|
|
147
|
+
<th key={header.id} colSpan={header.colSpan}>
|
|
148
|
+
{header.isPlaceholder ? null : <table.FlexRender header={header} />}
|
|
149
|
+
</th>
|
|
150
|
+
))}
|
|
151
|
+
</tr>
|
|
152
|
+
))}
|
|
153
|
+
</thead>
|
|
154
|
+
<tbody>
|
|
155
|
+
{table.getRowModel().rows.map((row) => (
|
|
156
|
+
<tr key={row.id}>
|
|
157
|
+
{row.getVisibleCells().map((cell) => (
|
|
158
|
+
<td key={cell.id}><table.FlexRender cell={cell} /></td>
|
|
159
|
+
))}
|
|
160
|
+
</tr>
|
|
161
|
+
))}
|
|
162
|
+
</tbody>
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
The `getAll*` accessors do NOT consult `columnVisibility` state. Only `Visible` variants and header-group APIs filter by visibility.
|
|
166
|
+
|
|
167
|
+
Source: docs/guide/column-visibility.md; examples/react/column-visibility/src/main.tsx
|
|
168
|
+
|
|
169
|
+
### [HIGH] `columnResizeMode: 'onChange'` + `column.getSize()` per cell + un-memoized body
|
|
170
|
+
|
|
171
|
+
Wrong:
|
|
172
|
+
|
|
173
|
+
```tsx
|
|
174
|
+
const table = useTable({
|
|
175
|
+
_features: tableFeatures({ columnSizingFeature, columnResizingFeature }),
|
|
176
|
+
columnResizeMode: 'onChange',
|
|
177
|
+
})
|
|
178
|
+
<td style={{ width: cell.column.getSize() }}>{cell.renderValue()}</td>
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Correct:
|
|
182
|
+
|
|
183
|
+
```tsx
|
|
184
|
+
// See "Performant 'onChange' resize" above — CSS variables + memoized body
|
|
185
|
+
const columnSizeVars = React.useMemo(() => {
|
|
186
|
+
/* … */
|
|
187
|
+
}, [table.state.columnResizing, table.state.columnSizing])
|
|
188
|
+
|
|
189
|
+
{
|
|
190
|
+
table.store.state.columnResizing.isResizingColumn ? (
|
|
191
|
+
<MemoizedTableBody table={table} />
|
|
192
|
+
) : (
|
|
193
|
+
<TableBody table={table} />
|
|
194
|
+
)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
;<div
|
|
198
|
+
className="td"
|
|
199
|
+
style={{ width: `calc(var(--col-${cell.column.id}-size) * 1px)` }}
|
|
200
|
+
/>
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
`'onChange'` commits a new `columnSizing` map on every pointer move. Per-cell `getSize()` blows the 16ms frame budget. The CSS-variable pattern caches widths once per resize batch.
|
|
204
|
+
|
|
205
|
+
Source: docs/guide/column-resizing.md; examples/react/column-resizing-performant/src/main.tsx
|
|
206
|
+
|
|
207
|
+
### [HIGH] Using v8 `enablePinning` at the table level
|
|
208
|
+
|
|
209
|
+
Wrong:
|
|
210
|
+
|
|
211
|
+
```ts
|
|
212
|
+
// v8 syntax — no longer disables pinning at table level in v9
|
|
213
|
+
const table = useTable({
|
|
214
|
+
_features: tableFeatures({ columnPinningFeature }),
|
|
215
|
+
enablePinning: false, // ignored
|
|
216
|
+
})
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Correct:
|
|
220
|
+
|
|
221
|
+
```ts
|
|
222
|
+
// v9 split: two distinct table-level options
|
|
223
|
+
const table = useTable({
|
|
224
|
+
_features: tableFeatures({ columnPinningFeature, rowPinningFeature }),
|
|
225
|
+
enableColumnPinning: false,
|
|
226
|
+
enableRowPinning: false,
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
// Per-column opt-out is still spelled `enablePinning`:
|
|
230
|
+
columnHelper.accessor('id', {
|
|
231
|
+
enablePinning: false, // this column can't be pinned
|
|
232
|
+
})
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
v9 split `enablePinning` into `enableColumnPinning` and `enableRowPinning`. The bare name now refers ONLY to per-column opt-out.
|
|
236
|
+
|
|
237
|
+
Source: packages/table-core/src/features/column-pinning/columnPinningFeature.types.ts
|
|
238
|
+
|
|
239
|
+
### [HIGH] Defining `columns` inline (infinite loop once a layout feature commits state)
|
|
240
|
+
|
|
241
|
+
Wrong:
|
|
242
|
+
|
|
243
|
+
```tsx
|
|
244
|
+
function App() {
|
|
245
|
+
const columns = [
|
|
246
|
+
columnHelper.accessor('firstName', {
|
|
247
|
+
/* … */
|
|
248
|
+
}),
|
|
249
|
+
columnHelper.accessor('lastName', {
|
|
250
|
+
/* … */
|
|
251
|
+
}),
|
|
252
|
+
]
|
|
253
|
+
const table = useTable({
|
|
254
|
+
_features: tableFeatures({ columnPinningFeature, columnResizingFeature }),
|
|
255
|
+
columns,
|
|
256
|
+
data,
|
|
257
|
+
})
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Correct:
|
|
262
|
+
|
|
263
|
+
```tsx
|
|
264
|
+
const defaultColumns = columnHelper.columns([
|
|
265
|
+
columnHelper.accessor('firstName', {
|
|
266
|
+
/* … */
|
|
267
|
+
}),
|
|
268
|
+
columnHelper.accessor('lastName', {
|
|
269
|
+
/* … */
|
|
270
|
+
}),
|
|
271
|
+
])
|
|
272
|
+
function App() {
|
|
273
|
+
const [columns] = React.useState(() => [...defaultColumns])
|
|
274
|
+
const table = useTable({ _features, columns, data })
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// or: useMemo
|
|
278
|
+
const columns = React.useMemo(
|
|
279
|
+
() =>
|
|
280
|
+
columnHelper.columns([
|
|
281
|
+
/* … */
|
|
282
|
+
]),
|
|
283
|
+
[],
|
|
284
|
+
)
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
Layout features commit state on every interaction. An inline `columns` array gets a new identity each render → table rebuild → another render. FAQ Pitfall 1.
|
|
288
|
+
|
|
289
|
+
Source: docs/faq.md; examples/react/column-pinning-split/src/main.tsx; examples/react/column-dnd/src/main.tsx
|
|
290
|
+
|
|
291
|
+
### [CRITICAL] Reimplementing visibility / pinning / resize logic manually
|
|
292
|
+
|
|
293
|
+
Wrong:
|
|
294
|
+
|
|
295
|
+
```ts
|
|
296
|
+
// Hand-rolled hide/show with a separate set
|
|
297
|
+
const [hidden, setHidden] = useState(new Set<string>())
|
|
298
|
+
const visibleColumns = useMemo(
|
|
299
|
+
() => columns.filter((c) => !hidden.has(c.id)),
|
|
300
|
+
[columns, hidden],
|
|
301
|
+
)
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
Correct:
|
|
305
|
+
|
|
306
|
+
```ts
|
|
307
|
+
const table = useTable({
|
|
308
|
+
_features: tableFeatures({ columnVisibilityFeature }),
|
|
309
|
+
_rowModels: {},
|
|
310
|
+
columns,
|
|
311
|
+
data,
|
|
312
|
+
})
|
|
313
|
+
column.toggleVisibility()
|
|
314
|
+
column.getIsVisible()
|
|
315
|
+
table.getVisibleLeafColumns()
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
Source: maintainer interview (Phase 4, 2026-05-17)
|
|
319
|
+
|
|
320
|
+
## See also
|
|
321
|
+
|
|
322
|
+
- `tanstack-table/state-management` — `state.columnVisibility` / `columnOrder` / `columnPinning` / `columnSizing` slices
|
|
323
|
+
- `tanstack-table/row-pinning` — analogous pinning for rows (different render pipeline)
|
|
324
|
+
- `tanstack-table/grouping` — `groupedColumnMode` interacts with `columnOrder`
|
|
325
|
+
|
|
326
|
+
## References
|
|
327
|
+
|
|
328
|
+
- [subsystems.md](references/subsystems.md) — full API surface per UI-state subsystem (visibility, ordering, pinning, sizing, resizing) plus MEDIUM-priority failure modes: reorder-pinned-via-`columnOrder`, react-dnd / react-beautiful-dnd avoidance, touch-resize handler
|