Skip to content

Commit 72ab26a

Browse files
authoredMay 7, 2024··
docs: data and header group docs (#5526)
1 parent e80b802 commit 72ab26a

File tree

7 files changed

+359
-83
lines changed

7 files changed

+359
-83
lines changed
 

‎docs/config.json

+16-12
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@
2121
"label": "Installation",
2222
"to": "installation"
2323
},
24+
{
25+
"label": "Migrating to V8",
26+
"to": "guide/migrating"
27+
},
2428
{
2529
"label": "FAQ",
2630
"to": "faq"
@@ -31,7 +35,7 @@
3135
"label": "qwik",
3236
"children": [
3337
{
34-
"label": "Qwik Table",
38+
"label": "Qwik Table Adapter",
3539
"to": "framework/qwik/qwik-table"
3640
}
3741
]
@@ -40,7 +44,7 @@
4044
"label": "react",
4145
"children": [
4246
{
43-
"label": "React Table",
47+
"label": "React Table Adapter",
4448
"to": "framework/react/react-table"
4549
}
4650
]
@@ -49,7 +53,7 @@
4953
"label": "solid",
5054
"children": [
5155
{
52-
"label": "Solid Table",
56+
"label": "Solid Table Adapter",
5357
"to": "framework/solid/solid-table"
5458
}
5559
]
@@ -58,7 +62,7 @@
5862
"label": "svelte",
5963
"children": [
6064
{
61-
"label": "Svelte Table",
65+
"label": "Svelte Table Adapter",
6266
"to": "framework/svelte/svelte-table"
6367
}
6468
]
@@ -67,7 +71,7 @@
6771
"label": "vue",
6872
"children": [
6973
{
70-
"label": "Vue Table",
74+
"label": "Vue Table Adapter",
7175
"to": "framework/vue/vue-table"
7276
}
7377
]
@@ -76,7 +80,7 @@
7680
"label": "vanilla",
7781
"children": [
7882
{
79-
"label": "Vanilla JS/TS",
83+
"label": "Vanilla JS (No Framework)",
8084
"to": "vanilla"
8185
}
8286
]
@@ -87,17 +91,17 @@
8791
"label": "Core Guides",
8892
"children": [
8993
{
90-
"label": "Migrating to V8",
91-
"to": "guide/migrating"
92-
},
93-
{
94-
"label": "Table Instance",
95-
"to": "guide/tables"
94+
"label": "Data (and TypeScript)",
95+
"to": "guide/data"
9696
},
9797
{
9898
"label": "Column Defs",
9999
"to": "guide/column-defs"
100100
},
101+
{
102+
"label": "Table Instance",
103+
"to": "guide/tables"
104+
},
101105
{
102106
"label": "Rows Models",
103107
"to": "guide/row-models"

‎docs/guide/column-defs.md

+33-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ title: Columns Guide
44

55
## API
66

7-
[Table API](../../api/core/table)
7+
[Column Def](../../api/core/column-def)
88

99
## Column Definitions Guide
1010

@@ -145,6 +145,38 @@ columnHelper.accessor('firstName')
145145
}
146146
```
147147

148+
## Deep Keys
149+
150+
If each of your items is an object with the following shape:
151+
152+
```tsx
153+
type Person = {
154+
name: {
155+
first: string
156+
last: string
157+
}
158+
info: {
159+
age: number
160+
visits: number
161+
}
162+
}
163+
```
164+
165+
You could extract the `first` value like so:
166+
167+
```tsx
168+
columnHelper.accessor('name.first'), {
169+
id: 'firstName',
170+
}
171+
172+
// OR
173+
174+
{
175+
accessorKey: 'name.first',
176+
id: 'firstName',
177+
}
178+
```
179+
148180
## Array Indices
149181

150182
If each of your items is an array with the following shape:

‎docs/guide/column-filtering.md

+8-8
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ title: Column Filtering Guide
66

77
Want to skip to the implementation? Check out these examples:
88

9-
- [filters](../../framework/react/examples/filters) (includes faceting)
10-
- [filters-faceted](../../framework/react/examples/filters-faceted)
11-
- [filters-fuzzy](../../framework/react/examples/filters-fuzzy)
12-
- [editable-data](../../framework/react/examples/editable-data)
13-
- [expanding](../../framework/react/examples/expanding)
14-
- [grouping](../../framework/react/examples/grouping)
15-
- [pagination](../../framework/react/examples/pagination)
16-
- [row-selection](../../framework/react/examples/row-selection)
9+
- [Column Filters](../../framework/react/examples/filters)
10+
- [Faceted Filters](../../framework/react/examples/filters-faceted) (Autocomplete and Range filters)
11+
- [Fuzzy Search](../../framework/react/examples/filters-fuzzy) (Match Sorter)
12+
- [Editable Data](../../framework/react/examples/editable-data)
13+
- [Expanding](../../framework/react/examples/expanding) (Filtering from Sub-Rows)
14+
- [Grouping](../../framework/react/examples/grouping)
15+
- [Pagination](../../framework/react/examples/pagination)
16+
- [Row Selection](../../framework/react/examples/row-selection)
1717

1818
## API
1919

‎docs/guide/data.md

+250
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
---
2+
title: Data Guide
3+
---
4+
5+
## Data (and TypeScript) Guide
6+
7+
Tables start with your data. Your column definitions and rows will depend on the shape of your data. TanStack Table has some TypeScript features that will help you create the rest of your table code with a great type-safe experience. If you set up your data and types correctly, TanStack Table will be able to infer the shape of your data and enforce that your column definitions are made correctly.
8+
9+
### TypeScript
10+
11+
TypeScript is NOT required to use the TanStack Table packages... ***BUT*** TanStack Table is written and organized in such a way that makes the awesome TypeScript experience that you get feel like it is one of the main selling points of the library. If you are not using TypeScript, you will be missing out on a lot of great autocompletion and type-checking features that will both speed up your development time and reduce the number of bugs in your code.
12+
13+
#### TypeScript Generics
14+
15+
Having a basic understanding of what TypeScript Generics are and how they work will help you understand this guide better, but it should be easy enough to pick up as you go. The official [TypeScript Generics Docs](https://www.typescriptlang.org/docs/handbook/2/generics.html) may be helpful for those not yet familiar with TypeScript.
16+
17+
### Defining Data Types
18+
19+
`data` is an array of objects that will be turned into the rows of your table. Each object in the array represents a row of data (under normal circumstances). If you are using TypeScript, we usually define a type for the shape of our data. This type is used as a generic type for all of the other table, column, row, and cell instances. This Generic is usually referred to as `TData` throughout the rest of the TanStack Table types and APIs.
20+
21+
For example, if we have a table that displays a list of users in an array like this:
22+
23+
```json
24+
[
25+
{
26+
"firstName": "Tanner",
27+
"lastName": "Linsley",
28+
"age": 33,
29+
"visits": 100,
30+
"progress": 50,
31+
"status": "Married"
32+
},
33+
{
34+
"firstName": "Kevin",
35+
"lastName": "Vandy",
36+
"age": 27,
37+
"visits": 200,
38+
"progress": 100,
39+
"status": "Single"
40+
}
41+
]
42+
```
43+
44+
Then we can define a User (TData) type like this:
45+
46+
```ts
47+
//TData
48+
type User = {
49+
firstName: string
50+
lastName: string
51+
age: number
52+
visits: number
53+
progress: number
54+
status: string
55+
}
56+
```
57+
58+
We can then define our `data` array with this type, and then TanStack Table will be able to intelligently infer lots of types for us later on in our columns, rows, cells, etc. This is because the `data` type is literally defined as the `TData` generic type. Whatever you pass to the `data` table option will become the `TData` type for the rest of the table instance. Just make sure your column definitions use the same `TData` type as the `data` type when you define them later.
59+
60+
```ts
61+
//note: data needs a "stable" reference in order to prevent infinite re-renders
62+
const data: User[] = []
63+
//or
64+
const [data, setData] = React.useState<User[]>([])
65+
//or
66+
const data = ref<User[]>([]) //vue
67+
//etc...
68+
```
69+
70+
#### Deep Keyed Data
71+
72+
If your data is not a nice flat array of objects, that's okay! Once you get around to defining your columns, there are strategies for accessing deeply nested data in your accessors.
73+
74+
If your `data` looks something like this:
75+
76+
```json
77+
[
78+
{
79+
"name": {
80+
"first": "Tanner",
81+
"last": "Linsley"
82+
},
83+
"info": {
84+
"age": 33,
85+
"visits": 100,
86+
}
87+
},
88+
{
89+
"name": {
90+
"first": "Kevin",
91+
"last": "Vandy"
92+
},
93+
"info": {
94+
"age": 27,
95+
"visits": 200,
96+
}
97+
}
98+
]
99+
```
100+
101+
You can define a type like this:
102+
103+
```ts
104+
type User = {
105+
name: {
106+
first: string
107+
last: string
108+
}
109+
info: {
110+
age: number
111+
visits: number
112+
}
113+
}
114+
```
115+
116+
And you will be able to access the data in your column definitions with either dot notation in an accessorKey or simply by using an accessorFn.
117+
118+
```ts
119+
const columns = [
120+
{
121+
header: 'First Name',
122+
accessorKey: 'name.first',
123+
},
124+
{
125+
header: 'Last Name',
126+
accessorKey: 'name.last',
127+
},
128+
{
129+
header: 'Age',
130+
accessorFn: info => info.age,
131+
},
132+
//...
133+
]
134+
```
135+
136+
This is discussed in more detail in the [Column Def Guide](../column-defs).
137+
138+
> NOTE: The "keys" in your json data can usually be anything, but any periods in the keys will be interpreted as a deep key and will cause errors.
139+
140+
#### Nested Sub-Row Data
141+
142+
If you are using expanding features, it can be common to have nested sub-rows in your data. This results in a recursive type that is a bit different.
143+
144+
So if your data looks like this:
145+
146+
```json
147+
[
148+
{
149+
"firstName": "Tanner",
150+
"lastName": "Linsley",
151+
"subRows": [
152+
{
153+
"firstName": "Kevin",
154+
"lastName": "Vandy",
155+
},
156+
{
157+
"firstName": "John",
158+
"lastName": "Doe",
159+
"subRows": [
160+
//...
161+
]
162+
}
163+
]
164+
},
165+
{
166+
"firstName": "Jane",
167+
"lastName": "Doe",
168+
}
169+
]
170+
```
171+
172+
You can define a type like this:
173+
174+
```ts
175+
type User = {
176+
firstName: string
177+
lastName: string
178+
subRows?: User[] //does not have to be called "subRows", can be called anything
179+
}
180+
```
181+
182+
Where `subRows` is an optional array of `User` objects. This is discussed in more detail in the [Expanding Guide](../expanding).
183+
184+
### Give Data a "Stable" Reference
185+
186+
The `data` array that you pass to the table instance ***MUST*** have a "stable" reference in order to prevent bugs that cause infinite re-renders (especially in React).
187+
188+
This will depend on which framework adapter you are using, but in React, you should often use `React.useState`, `React.useMemo`, or similar to ensure that both the `data` and `columns` table options have stable references.
189+
190+
```tsx
191+
const fallbackData = []
192+
193+
export default function MyComponent() {
194+
//✅ GOOD: This will not cause an infinite loop of re-renders because `columns` is a stable reference
195+
const columns = useMemo(() => [
196+
// ...
197+
], []);
198+
199+
//✅ GOOD: This will not cause an infinite loop of re-renders because `data` is a stable reference
200+
const [data, setData] = useState(() => [
201+
// ...
202+
]);
203+
204+
// Columns and data are defined in a stable reference, will not cause infinite loop!
205+
const table = useReactTable({
206+
columns,
207+
data ?? fallbackData, //also good to use a fallback array that is defined outside of the component (stable reference)
208+
});
209+
210+
return <table>...</table>;
211+
}
212+
```
213+
214+
`React.useState` and `React.useMemo` are not the only ways to give your data a stable reference. You can also define your data outside of the component or use a 3rd party state management library like Redux, Zustand, or TanStack Query.
215+
216+
The main thing to avoid is defining the `data` array inside the same scope as the `useReactTable` call. That will cause the `data` array to be redefined on every render, which will cause an infinite loop of re-renders.
217+
218+
```tsx
219+
export default function MyComponent() {
220+
//😵 BAD: This will cause an infinite loop of re-renders because `columns` is redefined as a new array on every render!
221+
const columns = [
222+
// ...
223+
];
224+
225+
//😵 BAD: This will cause an infinite loop of re-renders because `data` is redefined as a new array on every render!
226+
const data = [
227+
// ...
228+
];
229+
230+
//❌ Columns and data are defined in the same scope as `useReactTable` without a stable reference, will cause infinite loop!
231+
const table = useReactTable({
232+
columns,
233+
data ?? [], //❌ Also bad because the fallback array is re-created on every render
234+
});
235+
236+
return <table>...</table>;
237+
}
238+
```
239+
240+
### How TanStack Table Transforms Data
241+
242+
Later, in other parts of these docs, you will see how TanStack Table processes the `data` that you pass to the table and generates the row and cell objects that are used to create the table. The `data` the you pass to the table is never mutated by TanStack Table, but the actual values in the rows and cells may be transformed by the accessors in your column definitions, or by other features performed by [row models](../row-models) like grouping or aggregation.
243+
244+
### How Much Data Can TanStack Table Handle?
245+
246+
Believe it or not, TanStack Table was actually built to scale up to handle potentially hundreds of thousands of rows of data in the client. This is obviously not always possible, depending on the size of each column's data and the number of columns. However, the sorting, filtering, pagination, and grouping features are all built with performance in mind for large datasets.
247+
248+
The default mindset of a developer building a data grid is to implement server-side pagination, sorting, and filtering for large datasets. This is still usually a good idea, but a lot of developers underestimate how much data can actually be handled in the client with modern browsers and the right optimizations. If your table will never have more than a few thousand rows, you can probably take advantage of the client-side features in TanStack Table instead of implementing them yourself on the server. Before committing to letting TanStack Table's client-side features handle your large dataset, you should test it with your actual data to see if it performs well enough for your needs, of course.
249+
250+
This is discussed in more detail in the [Pagination Guide](../pagination#should-you-use-client-side-pagination).

‎docs/guide/header-groups.md

+41-1
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,44 @@ title: Header Groups Guide
66

77
[Header Group API](../../api/core/header-group)
88

9-
## Header Groups Guide
9+
## Header Groups Guide
10+
11+
This quick guide will discuss the different ways you can retrieve and interact with header group objects in TanStack Table.
12+
13+
### What are Header Groups?
14+
15+
Header Groups are simply "rows" of headers. Don't let the name confuse you, it's just that simple. The large majority of tables will only have one row of headers (a single header group), but if you define your column structure with nested columns as with the [Column Groups example](../../framework/react/examples/column-groups), you can have multiple rows of headers (multiple header groups).
16+
17+
### Where to Get Header Groups From
18+
19+
There are multiple `table` instance APIs you can use to retrieve header groups from the table instance. `table.getHeaderGroups` is the most common API to use, but depending on the features that you are using, you may need to use other APIs, such as `table.get[Left/Center/Right]HeaderGroups` if you are using column pinning features.
20+
21+
### Header Group Objects
22+
23+
Header Group objects are similar to [Row](../rows) objects, though simpler since there is not as much going on in header rows as there are in the body rows.
24+
25+
By default, header groups only have three properties:
26+
27+
- `id`: The unique identifier for the header group that is generated from its depth (index). This is useful as a key for React components.
28+
- `depth`: The depth of the header group, zero-indexed based. Think of this as the row index amongst all header rows.
29+
- `headers`: An array of [Header](../headers) cell objects that belong to this header group (row).
30+
31+
### Access Header Cells
32+
33+
To render the header cells in a header group, you just map over the `headers` array from the header group object.
34+
35+
```jsx
36+
<thead>
37+
{table.getHeaderGroups().map(headerGroup => {
38+
return (
39+
<tr key={headerGroup.id}>
40+
{headerGroup.headers.map(header => ( // map over the headerGroup headers array
41+
<th key={header.id} colSpan={header.colSpan}>
42+
{/* */}
43+
</th>
44+
))}
45+
</tr>
46+
)
47+
})}
48+
</thead>
49+
```

‎docs/guide/tables.md

+10-59
Original file line numberDiff line numberDiff line change
@@ -16,58 +16,7 @@ To create a table instance, 2 `options` are required: `columns` and `data`. Ther
1616

1717
#### Defining Data
1818

19-
`data` is an array of objects that will be turned into the rows of your table. Each object in the array represents a row of data (under normal circumstances). If you are using TypeScript, we usually define a type for the shape of our data. This type is used as a generic type for all of the other table, column, row, and cell instances. This type is usually referred to as `TData`.
20-
21-
For example, if we have a table that displays a list of users in an array like this:
22-
23-
```json
24-
[
25-
{
26-
"firstName": "Tanner",
27-
"lastName": "Linsley",
28-
"age": 33,
29-
"visits": 100,
30-
"progress": 50,
31-
"status": "Married"
32-
},
33-
{
34-
"firstName": "Kevin",
35-
"lastName": "Vandy",
36-
"age": 27,
37-
"visits": 200,
38-
"progress": 100,
39-
"status": "Single"
40-
}
41-
]
42-
```
43-
44-
Then we can define a User (TData) type like this:
45-
46-
```ts
47-
//TData
48-
type User = {
49-
firstName: string
50-
lastName: string
51-
age: number
52-
visits: number
53-
progress: number
54-
status: string
55-
}
56-
```
57-
58-
We can then define our `data` array with this type, and then TanStack Table will be able to intelligently infer lots of types for us later on in our columns, rows, cells, etc.
59-
60-
```ts
61-
//note: data needs a "stable" reference in order to prevent infinite re-renders
62-
const data: User[] = []
63-
//or
64-
const [data, setData] = React.useState<User[]>([])
65-
//or
66-
const data = ref<User[]>([])
67-
//etc...
68-
```
69-
70-
> Note: `data` needs a "stable" reference (especially in React) in order to prevent infinite re-renders. This is why we recommend using `React.useState` or `React.useMemo`, or defining your data outside of the same react component that creates the table instance, or using a library like TanStack Query to manage your data state.
19+
Define your data as an array of objects with a stable reference. `data` can come from anywhere like an API response or defined statically in your code, but it must have a stable reference to prevent infinite re-renders. If using TypeScript, the the type that you give your data will be used as a `TData` generic. See the [Data Guide](../data) for more info.
7120

7221
#### Defining Columns
7322

@@ -81,25 +30,25 @@ const columnHelper = createColumnHelper<User>() //Pass User type as the generic
8130

8231
The column definitions are where we will tell TanStack Table how each column should access and/or transform row data with either an `accessorKey` or `accessorFn`. See the [Column Def Guide](../column-defs#creating-accessor-columns) for more info.
8332

84-
#### Creating the Table Instance
33+
#### Initializing the Table Instance
8534

86-
With our `columns` and `data` defined, we can now create our basic table instance.
35+
With our `columns` and `data` defined, we can now create our basic table instance, along side the required row models and any other table options that we want to pass in.
8736

8837
```ts
8938
//vanilla js
90-
const table = createTable({ columns, data })
39+
const table = createTable({ columns, data, getCoreRowModel: getCoreRowModel() })
9140

9241
//react
93-
const table = useReactTable({ columns, data })
42+
const table = useReactTable({ columns, data, getCoreRowModel: getCoreRowModel() })
9443

9544
//solid
96-
const table = createSolidTable({ columns, data })
45+
const table = createSolidTable({ columns, data, getCoreRowModel: getCoreRowModel() })
9746

9847
//svelte
99-
const table = createSvelteTable({ columns, data })
48+
const table = createSvelteTable({ columns, data, getCoreRowModel: getCoreRowModel() })
10049

10150
//vue
102-
const table = useVueTable({ columns, data })
51+
const table = useVueTable({ columns, data, getCoreRowModel: getCoreRowModel() })
10352
```
10453

10554
So what's in the `table` instance? Let's take a look at what interactions we can have with the table instance.
@@ -116,6 +65,8 @@ table.setRowSelection((old) => ({...old})) //set the row selection state
11665
table.resetRowSelection() //reset the row selection state
11766
```
11867

68+
This is covered in more detail in the [Table State Guides](../../framework/react/guide/table-state)
69+
11970
### Table APIs
12071

12172
There are dozens of table APIs created by each feature to help you either read or mutate the table state in different ways.

‎examples/react/column-groups/src/main.tsx

+1-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import ReactDOM from 'react-dom/client'
44
import './index.css'
55

66
import {
7-
ColumnDef,
87
createColumnHelper,
98
flexRender,
109
getCoreRowModel,
@@ -97,7 +96,7 @@ const columns = [
9796
]
9897

9998
function App() {
100-
const [data, setData] = React.useState(() => [...defaultData])
99+
const [data, _setData] = React.useState(() => [...defaultData])
101100
const rerender = React.useReducer(() => ({}), {})[1]
102101

103102
const table = useReactTable({

0 commit comments

Comments
 (0)
Please sign in to comment.