0
# Column System
1
2
Comprehensive column definition and management system supporting accessor functions, display columns, grouped columns, and various column types with full TypeScript type safety.
3
4
## Capabilities
5
6
### Column Helper
7
8
Utility for creating strongly-typed column definitions with proper type inference and accessor patterns.
9
10
```typescript { .api }
11
/**
12
* Creates a typed column helper for building column definitions
13
* @returns ColumnHelper instance with type-safe methods
14
*/
15
function createColumnHelper<TData extends RowData>(): ColumnHelper<TData>;
16
17
interface ColumnHelper<TData extends RowData> {
18
/** Create accessor column with automatic type inference */
19
accessor<TAccessor extends AccessorFn<TData> | DeepKeys<TData>>(
20
accessor: TAccessor,
21
column: ColumnDefBase<TData, any>
22
): ColumnDef<TData, any>;
23
/** Create display-only column with no data access */
24
display(column: DisplayColumnDef<TData>): DisplayColumnDef<TData, unknown>;
25
/** Create grouped column with sub-columns */
26
group(column: GroupColumnDef<TData>): GroupColumnDef<TData, unknown>;
27
}
28
```
29
30
**Usage Examples:**
31
32
```typescript
33
import { createColumnHelper } from "@tanstack/table-core";
34
35
type Person = {
36
firstName: string;
37
lastName: string;
38
age: number;
39
address: {
40
street: string;
41
city: string;
42
};
43
};
44
45
const columnHelper = createColumnHelper<Person>();
46
47
// Accessor column with key
48
const firstNameColumn = columnHelper.accessor('firstName', {
49
header: 'First Name',
50
cell: info => info.getValue(),
51
});
52
53
// Accessor column with function
54
const fullNameColumn = columnHelper.accessor(
55
row => `${row.firstName} ${row.lastName}`,
56
{
57
id: 'fullName',
58
header: 'Full Name',
59
cell: info => info.getValue(),
60
}
61
);
62
63
// Deep accessor for nested properties
64
const cityColumn = columnHelper.accessor('address.city', {
65
header: 'City',
66
cell: info => info.getValue(),
67
});
68
69
// Display column
70
const actionsColumn = columnHelper.display({
71
id: 'actions',
72
header: 'Actions',
73
cell: props => (
74
<button onClick={() => console.log(props.row.original)}>
75
Edit
76
</button>
77
),
78
});
79
80
// Group column
81
const nameGroup = columnHelper.group({
82
header: 'Name',
83
columns: [firstNameColumn, lastNameColumn],
84
});
85
```
86
87
### Column Definitions
88
89
Core column definition types supporting different column patterns and behaviors.
90
91
```typescript { .api }
92
/** Union type of all possible column definitions */
93
type ColumnDef<TData extends RowData, TValue = unknown> =
94
| AccessorKeyColumnDef<TData, TValue>
95
| AccessorFnColumnDef<TData, TValue>
96
| DisplayColumnDef<TData, TValue>
97
| GroupColumnDef<TData, TValue>;
98
99
/** Base column definition with common properties */
100
interface ColumnDefBase<TData extends RowData, TValue = unknown> {
101
/** Unique identifier for the column */
102
id?: string;
103
/** Header content for the column */
104
header?: ColumnDefTemplate<HeaderContext<TData, TValue>>;
105
/** Footer content for the column */
106
footer?: ColumnDefTemplate<HeaderContext<TData, TValue>>;
107
/** Cell content renderer */
108
cell?: ColumnDefTemplate<CellContext<TData, TValue>>;
109
/** Custom meta information for the column */
110
meta?: ColumnMeta<TData, TValue>;
111
/** Enable/disable this specific column */
112
enableHiding?: boolean;
113
}
114
115
/** Column definition using property key accessor */
116
interface AccessorKeyColumnDef<TData extends RowData, TValue = unknown>
117
extends ColumnDefBase<TData, TValue> {
118
/** Property key to access from row data */
119
accessorKey: DeepKeys<TData>;
120
/** Optional accessor function override */
121
accessorFn?: AccessorFn<TData, TValue>;
122
}
123
124
/** Column definition using function accessor */
125
interface AccessorFnColumnDef<TData extends RowData, TValue = unknown>
126
extends ColumnDefBase<TData, TValue> {
127
/** Function to extract value from row data */
128
accessorFn: AccessorFn<TData, TValue>;
129
id: string;
130
}
131
132
/** Display column with no data access */
133
interface DisplayColumnDef<TData extends RowData, TValue = unknown>
134
extends ColumnDefBase<TData, TValue> {
135
id: string;
136
}
137
138
/** Group column containing sub-columns */
139
interface GroupColumnDef<TData extends RowData, TValue = unknown>
140
extends ColumnDefBase<TData, TValue> {
141
/** Array of sub-columns */
142
columns: ColumnDef<TData, any>[];
143
id?: string;
144
}
145
```
146
147
### Column Core Interface
148
149
The core column interface providing access to column properties and methods.
150
151
```typescript { .api }
152
interface Column<TData extends RowData, TValue = unknown> extends
153
CoreColumn<TData, TValue>,
154
VisibilityColumn,
155
ColumnOrderColumn,
156
ColumnPinningColumn,
157
FacetedColumn<TData>,
158
ColumnFiltersColumn<TData>,
159
GlobalFilterColumn,
160
SortingColumn<TData>,
161
GroupingColumn<TData>,
162
ColumnSizingColumn {}
163
164
interface CoreColumn<TData extends RowData, TValue = unknown> {
165
/** Unique column identifier */
166
id: string;
167
/** Depth of the column in nested structure */
168
depth: number;
169
/** Original column definition */
170
columnDef: ColumnDef<TData, TValue>;
171
/** Sub-columns if this is a group column */
172
columns: Column<TData, TValue>[];
173
/** Parent column if this is a sub-column */
174
parent?: Column<TData, TValue>;
175
/** Accessor function for extracting values */
176
accessorFn?: AccessorFn<TData, TValue>;
177
/** Get flattened array of all sub-columns */
178
getFlatColumns(): Column<TData, TValue>[];
179
/** Get array of leaf columns (no sub-columns) */
180
getLeafColumns(): Column<TData, TValue>[];
181
}
182
```
183
184
**Usage Examples:**
185
186
```typescript
187
// Access column properties
188
const column = table.getColumn('firstName');
189
console.log(column.id); // 'firstName'
190
console.log(column.depth); // 0
191
192
// Get nested columns
193
const groupColumn = table.getColumn('nameGroup');
194
const leafColumns = groupColumn.getLeafColumns();
195
196
// Check if column has sub-columns
197
const hasSubColumns = column.columns.length > 0;
198
```
199
200
### Accessor Functions
201
202
Functions for extracting values from row data with strong typing support.
203
204
```typescript { .api }
205
/** Function type for accessing row data values */
206
type AccessorFn<TData extends RowData, TValue = unknown> = (
207
originalRow: TData,
208
index: number
209
) => TValue;
210
211
/** Utility type for deep property key access */
212
type DeepKeys<T> = T extends Record<string, any>
213
? {
214
[K in keyof T]-?: K extends string | number
215
? T[K] extends Record<string, any>
216
? `${K}` | `${K}.${DeepKeys<T[K]>}`
217
: `${K}`
218
: never;
219
}[keyof T]
220
: never;
221
222
/** Utility type for extracting deep property values */
223
type DeepValue<T, TProp extends DeepKeys<T>> = T extends Record<string, any>
224
? TProp extends `${infer TKey}.${infer TRest}`
225
? TKey extends keyof T
226
? TRest extends DeepKeys<T[TKey]>
227
? DeepValue<T[TKey], TRest>
228
: never
229
: never
230
: TProp extends keyof T
231
? T[TProp]
232
: never
233
: never;
234
```
235
236
**Usage Examples:**
237
238
```typescript
239
type User = {
240
profile: {
241
personal: {
242
name: string;
243
age: number;
244
};
245
contact: {
246
email: string;
247
};
248
};
249
};
250
251
// Deep key examples
252
type NameKey = 'profile.personal.name'; // Valid
253
type EmailKey = 'profile.contact.email'; // Valid
254
255
// Accessor function examples
256
const nameAccessor: AccessorFn<User, string> = (row, index) =>
257
row.profile.personal.name;
258
259
const ageAccessor: AccessorFn<User, number> = (row, index) =>
260
row.profile.personal.age;
261
262
// Using with column helper
263
const nameColumn = columnHelper.accessor('profile.personal.name', {
264
header: 'Name',
265
cell: info => info.getValue(), // Type: string
266
});
267
```
268
269
### Column Templates
270
271
Flexible templating system for column headers, cells, and footers.
272
273
```typescript { .api }
274
/** Template type that can be a value or function */
275
type ColumnDefTemplate<TProps> =
276
| string
277
| ((props: TProps) => any);
278
279
/** Template rendering function */
280
type StringOrTemplateHeader<TData extends RowData, TValue = unknown> =
281
| string
282
| ((props: HeaderContext<TData, TValue>) => any);
283
```
284
285
**Usage Examples:**
286
287
```typescript
288
// String template
289
const simpleColumn = columnHelper.accessor('name', {
290
header: 'Name',
291
cell: 'Default Cell Content',
292
});
293
294
// Function template
295
const complexColumn = columnHelper.accessor('status', {
296
header: ({ column }) => (
297
<button onClick={() => column.toggleSorting()}>
298
Status {column.getIsSorted() === 'asc' ? '↑' : column.getIsSorted() === 'desc' ? '↓' : ''}
299
</button>
300
),
301
cell: ({ getValue, row }) => {
302
const status = getValue();
303
return (
304
<span className={`status-${status}`}>
305
{status} ({row.original.id})
306
</span>
307
);
308
},
309
});
310
```
311
312
### Column Metadata
313
314
Custom metadata system for attaching additional information to columns.
315
316
```typescript { .api }
317
/** Custom metadata interface for columns */
318
interface ColumnMeta<TData extends RowData, TValue = unknown> {
319
/** Any custom properties */
320
[key: string]: any;
321
}
322
```
323
324
**Usage Examples:**
325
326
```typescript
327
const columnWithMeta = columnHelper.accessor('price', {
328
header: 'Price',
329
meta: {
330
type: 'currency',
331
format: 'USD',
332
validation: {
333
required: true,
334
min: 0,
335
},
336
className: 'text-right font-mono',
337
},
338
cell: ({ getValue, column }) => {
339
const value = getValue();
340
const meta = column.columnDef.meta;
341
342
if (meta?.type === 'currency') {
343
return new Intl.NumberFormat('en-US', {
344
style: 'currency',
345
currency: meta.format || 'USD',
346
}).format(value);
347
}
348
349
return value;
350
},
351
});
352
353
// Access meta in rendering
354
const meta = column.columnDef.meta;
355
```
356
357
### Column Resolution
358
359
Internal column definition resolution and processing.
360
361
```typescript { .api }
362
/** Resolved column definition after processing */
363
interface ColumnDefResolved<TData extends RowData, TValue = unknown>
364
extends ColumnDefBase<TData, TValue> {
365
/** Resolved accessor function */
366
accessorFn?: AccessorFn<TData, TValue>;
367
/** Resolved column ID */
368
id: string;
369
}
370
371
/** Creates a resolved column from definition */
372
function createColumn<TData extends RowData, TValue = unknown>(
373
table: Table<TData>,
374
columnDef: ColumnDef<TData, TValue>,
375
depth: number,
376
parent?: Column<TData, any>
377
): Column<TData, TValue>;
378
```
379
380
This system automatically resolves column definitions, generates IDs when missing, and creates the appropriate accessor functions based on the column type.