Skip to content

Commit 6b4d616

Browse files
mahmudhamidKevinVandy
andauthoredSep 14, 2024··
docs: Updated some incomplete docs (#5741)
* Updated some incomplete docs * Update expanding.md Modified some information for clarity * Update expanding.md Fixed some typos * Update expanding.md fixed some typos * Update expanding.md * Update global-faceting.md * Update grouping.md * Update grouping.md * Update expanding.md * Update expanding.md * Update global-filtering.md * polish up new docs --------- Co-authored-by: Kevin Van Cott <kevinvandy656@gmail.com>
1 parent 7fe650d commit 6b4d616

File tree

5 files changed

+693
-4
lines changed

5 files changed

+693
-4
lines changed
 

‎docs/guide/expanding.md

+214-1
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,222 @@ Want to skip to the implementation? Check out these examples:
88

99
- [expanding](../../framework/react/examples/expanding)
1010
- [grouping](../../framework/react/examples/grouping)
11+
- [sub-components](../../framework/react/examples/sub-components)
1112

1213
## API
1314

1415
[Expanding API](../../api/features/expanding)
1516

16-
## Expanding Feature Guide
17+
## Expanding Feature Guide
18+
19+
Expanding is a feature that allows you to show and hide additional rows of data related to a specific row. This can be useful in cases where you have hierarchical data and you want to allow users to drill down into the data from a higher level. Or it can be useful for showing additional information related to a row.
20+
21+
### Different use cases for Expanding Features
22+
23+
There are multiple use cases for expanding features in TanStack Table that will be discussed below.
24+
25+
1. Expanding sub-rows (child rows, aggregate rows, etc.)
26+
2. Expanding custom UI (detail panels, sub-tables, etc.)
27+
28+
### Enable Client-Side Expanding
29+
30+
To use the client-side expanding features, you need to define the getExpandedRowModel function in your table options. This function is responsible for returning the expanded row model.
31+
32+
```ts
33+
const table = useReactTable({
34+
// other options...
35+
getExpandedRowModel: getExpandedRowModel(),
36+
})
37+
```
38+
39+
Expanded data can either contain table rows or any other data you want to display. We will discuss how to handle both cases in this guide.
40+
41+
### Table rows as expanded data
42+
43+
Expanded rows are essentially child rows that inherit the same column structure as their parent rows. If your data object already includes these expanded rows data, you can utilize the `getSubRows` function to specify these child rows. However, if your data object does not contain the expanded rows data, they can be treated as custom expanded data, which is discussed in next section.
44+
45+
For example, if you have a data object like this:
46+
47+
```ts
48+
type Person = {
49+
id: number
50+
name: string
51+
age: number
52+
children: Person[]
53+
}
54+
55+
const data: Person = [
56+
{ id: 1,
57+
name: 'John',
58+
age: 30,
59+
children: [
60+
{ id: 2, name: 'Jane', age: 5 },
61+
{ id: 5, name: 'Jim', age: 10 }
62+
]
63+
},
64+
{ id: 3,
65+
name: 'Doe',
66+
age: 40,
67+
children: [
68+
{ id: 4, name: 'Alice', age: 10 }
69+
]
70+
},
71+
]
72+
```
73+
74+
Then you can use the getSubRows function to return the children array in each row as expanded rows. The table instance will now understand where to look for the sub rows on each row.
75+
76+
```ts
77+
const table = useReactTable({
78+
// other options...
79+
getSubRows: (row) => row.children, // return the children array as sub-rows
80+
getCoreRowModel: getCoreRowModel(),
81+
getExpandedRowModel: getExpandedRowModel(),
82+
})
83+
```
84+
85+
> **Note:** You can have a complicated `getSubRows` function, but keep in mind that it will run for every row and every sub-row. This can be expensive if the function is not optimized. Async functions are not supported.
86+
87+
### Custom Expanding UI
88+
89+
In some cases, you may wish to show extra details or information, which may or may not be part of your table data object, such as expanded data for rows. This kind of expanding row UI has gone by many names over the years including "expandable rows", "detail panels", "sub-components", etc.
90+
91+
By default, the `row.getCanExpand()` row instance API will return false unless it finds `subRows` on a row. This can be overridden by implementing your own `getRowCanExpand` function in the table instance options.
92+
93+
```ts
94+
//...
95+
const table = useReactTable({
96+
// other options...
97+
getRowCanExpand: (row) => true, // Add your logic to determine if a row can be expanded. True means all rows include expanded data
98+
getCoreRowModel: getCoreRowModel(),
99+
getExpandedRowModel: getExpandedRowModel(),
100+
})
101+
//...
102+
<tbody>
103+
{table.getRowModel().rows.map((row) => (
104+
<React.Fragment key={row.id}>
105+
{/* Normal row UI */}
106+
<tr>
107+
{row.getVisibleCells().map((cell) => (
108+
<td key={cell.id}>
109+
<FlexRender
110+
render={cell.column.columnDef.cell}
111+
props={cell.getContext()}
112+
/>
113+
</td>
114+
))}
115+
</tr>
116+
{/* If the row is expanded, render the expanded UI as a separate row with a single cell that spans the width of the table */}
117+
{row.getIsExpanded() && (
118+
<tr>
119+
<td colSpan={row.getAllCells().length}> // The number of columns you wish to span for the expanded data if it is not a row that shares the same columns as the parent row
120+
// Your custom UI goes here
121+
</td>
122+
</tr>
123+
)}
124+
</React.Fragment>
125+
))}
126+
</tbody>
127+
//...
128+
```
129+
130+
### Expanded rows state
131+
132+
If you need to control the expanded state of the rows in your table, you can do so by using the expanded state and the `onExpandedChange` option. This allows you to manage the expanded state according to your requirements.
133+
134+
```ts
135+
const [expanded, setExpanded] = useState<ExpandedState>({})
136+
137+
const table = useReactTable({
138+
// other options...
139+
state: {
140+
expanded: expanded, // must pass expanded state back to the table
141+
},
142+
onExpandedChange: setExpanded
143+
})
144+
```
145+
146+
The ExpandedState type is defined as follows:
147+
148+
```ts
149+
type ExpandedState = true | Record<string, boolean>
150+
```
151+
152+
If the ExpandedState is true, it means all rows are expanded. If it's a record, only the rows with IDs present as keys in the record and have their value set to true are expanded. For example, if the expanded state is { row1: true, row2: false }, it means the row with ID row1 is expanded and the row with ID row2 is not expanded. This state is used by the table to determine which rows are expanded and should display their subRows, if any.
153+
154+
### UI toggling handler for expanded rows
155+
156+
TanStack table will not add a toggling handler UI for expanded data to your table. You should manually add it within each row's UI to allow users to expand and collapse the row. For example, you can add a button UI within the columns definition.
157+
158+
```ts
159+
const columns = [
160+
{
161+
accessorKey: 'name',
162+
header: 'Name',
163+
},
164+
{
165+
accessorKey: 'age',
166+
header: 'Age',
167+
},
168+
{
169+
header: 'Children',
170+
cell: ({ row }) => {
171+
return row.getCanExpand() ?
172+
<button
173+
onClick={row.getToggleExpandedHandler()}
174+
style={{ cursor: 'pointer' }}
175+
>
176+
{row.getIsExpanded() ? '👇' : '👉'}
177+
</button>
178+
: '';
179+
},
180+
},
181+
]
182+
```
183+
184+
### Filtering Expanded Rows
185+
186+
By default, the filtering process starts from the parent rows and moves downwards. This means if a parent row is excluded by the filter, all its child rows will also be excluded. However, you can change this behavior by using the `filterFromLeafRows` option. When this option is enabled, the filtering process starts from the leaf (child) rows and moves upwards. This ensures that a parent row will be included in the filtered results as long as at least one of its child or grandchild rows meets the filter criteria. Additionally, you can control how deep into the child hierarchy the filter process goes by using the `maxLeafRowFilterDepth` option. This option allows you to specify the maximum depth of child rows that the filter should consider.
187+
188+
```ts
189+
//...
190+
const table = useReactTable({
191+
// other options...
192+
getSubRows: row => row.subRows,
193+
getCoreRowModel: getCoreRowModel(),
194+
getFilteredRowModel: getFilteredRowModel(),
195+
getExpandedRowModel: getExpandedRowModel(),
196+
filterFromLeafRows: true, // search through the expanded rows
197+
maxLeafRowFilterDepth: 1, // limit the depth of the expanded rows that are searched
198+
})
199+
```
200+
201+
### Paginating Expanded Rows
202+
203+
By default, expanded rows are paginated along with the rest of the table (which means expanded rows may span multiple pages). If you want to disable this behavior (which means expanded rows will always render on their parents page. This also means more rows will be rendered than the set page size) you can use the `paginateExpandedRows` option.
204+
205+
```ts
206+
const table = useReactTable({
207+
// other options...
208+
paginateExpandedRows: false,
209+
})
210+
```
211+
212+
### Pinning Expanded Rows
213+
214+
Pinning expanded rows works the same way as pinning regular rows. You can pin expanded rows to the top or bottom of the table. Please refer to the [Pinning Guide](./pinning.md) for more information on row pinning.
215+
216+
### Sorting Expanded Rows
217+
218+
By default, expanded rows are sorted along with the rest of the table.
219+
220+
### Manual Expanding (server-side)
221+
222+
If you are doing server-side expansion, you can enable manual row expansion by setting the manualExpanding option to true. This means that the `getExpandedRowModel` will not be used to expand rows and you would be expected to perform the expansion in your own data model.
223+
224+
```ts
225+
const table = useReactTable({
226+
// other options...
227+
manualExpanding: true,
228+
})
229+
```

‎docs/guide/fuzzy-filtering.md

+108
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,111 @@ Want to skip to the implementation? Check out these examples:
1414

1515
## Fuzzy Filtering Guide
1616

17+
Fuzzy filtering is a technique that allows you to filter data based on approximate matches. This can be useful when you want to search for data that is similar to a given value, rather than an exact match.
18+
19+
You can implement a client side fuzzy filtering by defining a custom filter function. This function should take in the row, columnId, and filter value, and return a boolean indicating whether the row should be included in the filtered data.
20+
21+
Fuzzy filtering is mostly used with global filtering, but you can also apply it to individual columns. We will discuss how to implement fuzzy filtering for both cases.
22+
23+
> **Note:** You will need to install the `@tanstack/match-sorter-utils` library to use fuzzy filtering.
24+
> TanStack Match Sorter Utils is a fork of [match-sorter](https://github.com/kentcdodds/match-sorter) by Kent C. Dodds. It was forked in order to work better with TanStack Table's row by row filtering approach.
25+
26+
Using the match-sorter libraries is optional, but the TanStack Match Sorter Utils library provides a great way to both fuzzy filter and sort by the rank information it returns, so that rows can be sorted by their closest matches to the search query.
27+
28+
### Defining a Custom Fuzzy Filter Function
29+
30+
Here's an example of a custom fuzzy filter function:
31+
32+
```typescript
33+
import { rankItem } from '@tanstack/match-sorter-utils';
34+
import { FilterFn } from '@tanstack/table';
35+
36+
const fuzzyFilter: FilterFn<any> = (row, columnId, value, addMeta) => {
37+
// Rank the item
38+
const itemRank = rankItem(row.getValue(columnId), value)
39+
40+
// Store the itemRank info
41+
addMeta({ itemRank })
42+
43+
// Return if the item should be filtered in/out
44+
return itemRank.passed
45+
}
46+
```
47+
48+
In this function, we're using the rankItem function from the @tanstack/match-sorter-utils library to rank the item. We then store the ranking information in the meta data of the row, and return whether the item passed the ranking criteria.
49+
50+
### Using Fuzzy Filtering with Global Filtering
51+
52+
To use fuzzy filtering with global filtering, you can specify the fuzzy filter function in the globalFilterFn option of the table instance:
53+
54+
```typescript
55+
const table = useReactTable({ // or your framework's equivalent function
56+
columns,
57+
data,
58+
filterFns: {
59+
fuzzy: fuzzyFilter, //define as a filter function that can be used in column definitions
60+
},
61+
globalFilterFn: 'fuzzy', //apply fuzzy filter to the global filter (most common use case for fuzzy filter)
62+
getCoreRowModel: getCoreRowModel(),
63+
getFilteredRowModel: getFilteredRowModel(), //client side filtering
64+
getSortedRowModel: getSortedRowModel(), //client side sorting needed if you want to use sorting too.
65+
})
66+
```
67+
68+
### Using Fuzzy Filtering with Column Filtering
69+
70+
To use fuzzy filtering with column filtering, you should first define the fuzzy filter function in the filterFns option of the table instance. You can then specify the fuzzy filter function in the filterFn option of the column definition:
71+
72+
```typescript
73+
const column = [
74+
{
75+
accessorFn: row => `${row.firstName} ${row.lastName}`,
76+
id: 'fullName',
77+
header: 'Full Name',
78+
cell: info => info.getValue(),
79+
filterFn: 'fuzzy', //using our custom fuzzy filter function
80+
},
81+
// other columns...
82+
];
83+
```
84+
85+
In this example, we're applying the fuzzy filter to a column that combines the firstName and lastName fields of the data.
86+
87+
#### Sorting with Fuzzy Filtering
88+
89+
When using fuzzy filtering with column filtering, you might also want to sort the data based on the ranking information. You can do this by defining a custom sorting function:
90+
91+
```typescript
92+
import { compareItems } from '@tanstack/match-sorter-utils'
93+
import { sortingFns } from '@tanstack/table'
94+
95+
const fuzzySort: SortingFn<any> = (rowA, rowB, columnId) => {
96+
let dir = 0
97+
98+
// Only sort by rank if the column has ranking information
99+
if (rowA.columnFiltersMeta[columnId]) {
100+
dir = compareItems(
101+
rowA.columnFiltersMeta[columnId]?.itemRank!,
102+
rowB.columnFiltersMeta[columnId]?.itemRank!
103+
)
104+
}
105+
106+
// Provide an alphanumeric fallback for when the item ranks are equal
107+
return dir === 0 ? sortingFns.alphanumeric(rowA, rowB, columnId) : dir
108+
}
109+
```
110+
111+
In this function, we're comparing the ranking information of the two rows. If the ranks are equal, we fall back to alphanumeric sorting.
112+
113+
You can then specify this sorting function in the sortFn option of the column definition:
114+
115+
```typescript
116+
{
117+
accessorFn: row => `${row.firstName} ${row.lastName}`,
118+
id: 'fullName',
119+
header: 'Full Name',
120+
cell: info => info.getValue(),
121+
filterFn: 'fuzzy', //using our custom fuzzy filter function
122+
sortFn: 'fuzzySort', //using our custom fuzzy sort function
123+
}
124+
```

0 commit comments

Comments
 (0)
Please sign in to comment.