0
# Data Grouping
1
2
React Table provides comprehensive data grouping capabilities through the `useGroupBy` hook. This feature allows you to group rows by column values, create hierarchical data structures, and apply aggregation functions to grouped data.
3
4
## Capabilities
5
6
### Data Grouping (useGroupBy)
7
8
Enables row grouping by column values with support for multiple grouping levels, custom aggregation functions, and expandable group headers.
9
10
```javascript { .api }
11
/**
12
* Adds row grouping capabilities to the table
13
* @param hooks - Hook registration object
14
*/
15
function useGroupBy(hooks: Hooks): void;
16
17
/**
18
* Default grouping function that groups rows by column accessor values
19
* @param rows - Array of rows to group
20
* @param columnId - Column ID to group by
21
* @returns Grouped rows structure
22
*/
23
function defaultGroupByFn(rows: Row[], columnId: string): Row[];
24
25
interface GroupByInstance {
26
/** Toggle grouping for a specific column */
27
toggleGroupBy: (columnId: string, value?: boolean) => void;
28
/** Set the groupBy configuration */
29
setGroupBy: (groupBy: string[]) => void;
30
/** Rows before grouping was applied */
31
preGroupedRows: Row[];
32
/** Flat rows before grouping */
33
preGroupedFlatRows: Row[];
34
/** Rows after grouping */
35
groupedRows: Row[];
36
/** Flat rows after grouping */
37
groupedFlatRows: Row[];
38
/** Non-grouped rows mapped by ID */
39
nonGroupedRowsById: Record<string, Row>;
40
}
41
42
interface GroupByColumnInstance {
43
/** Whether this column can be grouped */
44
canGroupBy: boolean;
45
/** Whether this column is currently grouped */
46
isGrouped: boolean;
47
/** Index of this column in the groupBy array */
48
groupedIndex: number;
49
/** Toggle grouping for this column */
50
toggleGroupBy: (value?: boolean) => void;
51
/** Get props for group by toggle UI */
52
getGroupByToggleProps: (userProps?: any) => object;
53
}
54
55
interface GroupByState {
56
/** Array of column IDs to group by, in order */
57
groupBy: string[];
58
}
59
```
60
61
**Usage Examples:**
62
63
```javascript
64
import React from 'react';
65
import { useTable, useGroupBy } from 'react-table';
66
67
function GroupedTable({ columns, data }) {
68
const {
69
getTableProps,
70
getTableBodyProps,
71
headerGroups,
72
rows,
73
prepareRow,
74
state: { groupBy },
75
setGroupBy,
76
} = useTable(
77
{
78
columns,
79
data,
80
initialState: {
81
groupBy: ['category'], // Group by category initially
82
},
83
},
84
useGroupBy // Add grouping functionality
85
);
86
87
return (
88
<div>
89
<div>
90
<label>
91
Group By:
92
<select
93
value={groupBy[0] || ''}
94
onChange={e => setGroupBy(e.target.value ? [e.target.value] : [])}
95
>
96
<option value="">No Grouping</option>
97
<option value="category">Category</option>
98
<option value="status">Status</option>
99
</select>
100
</label>
101
</div>
102
103
<table {...getTableProps()}>
104
<thead>
105
{headerGroups.map(headerGroup => (
106
<tr {...headerGroup.getHeaderGroupProps()}>
107
{headerGroup.headers.map(column => (
108
<th {...column.getHeaderProps()}>
109
{column.render('Header')}
110
{column.canGroupBy && (
111
<button
112
{...column.getGroupByToggleProps()}
113
style={{
114
marginLeft: '8px',
115
backgroundColor: column.isGrouped ? '#007bff' : '#6c757d',
116
color: 'white',
117
border: 'none',
118
padding: '2px 6px',
119
borderRadius: '3px',
120
fontSize: '12px',
121
}}
122
>
123
{column.isGrouped ? 'Ungroup' : 'Group'}
124
</button>
125
)}
126
</th>
127
))}
128
</tr>
129
))}
130
</thead>
131
<tbody {...getTableBodyProps()}>
132
{rows.map(row => {
133
prepareRow(row);
134
135
// Group header row
136
if (row.isGrouped) {
137
return (
138
<tr {...row.getRowProps()}>
139
<td
140
{...row.cells[0].getCellProps()}
141
colSpan={columns.length}
142
style={{
143
fontWeight: 'bold',
144
backgroundColor: '#f8f9fa',
145
padding: '8px',
146
}}
147
>
148
{row.groupByID}: {row.groupByVal} ({row.subRows.length} items)
149
</td>
150
</tr>
151
);
152
}
153
154
// Regular data row
155
return (
156
<tr {...row.getRowProps()}>
157
{row.cells.map(cell => (
158
<td {...cell.getCellProps()}>
159
{cell.isGrouped ? (
160
<span style={{ fontWeight: 'bold' }}>
161
{cell.render('Cell')} ({row.subRows.length})
162
</span>
163
) : cell.isAggregated ? (
164
cell.render('Aggregated')
165
) : cell.isPlaceholder ? null : (
166
cell.render('Cell')
167
)}
168
</td>
169
))}
170
</tr>
171
);
172
})}
173
</tbody>
174
</table>
175
</div>
176
);
177
}
178
```
179
180
### Multi-level Grouping
181
182
Group by multiple columns to create nested hierarchical structures:
183
184
```javascript
185
const table = useTable(
186
{
187
columns,
188
data,
189
initialState: {
190
groupBy: ['category', 'status'], // Group by category, then status
191
},
192
},
193
useGroupBy
194
);
195
```
196
197
### Custom Aggregation Functions
198
199
Define how grouped data should be aggregated for display:
200
201
```javascript
202
const columns = [
203
{
204
Header: 'Product',
205
accessor: 'product',
206
},
207
{
208
Header: 'Category',
209
accessor: 'category',
210
},
211
{
212
Header: 'Sales',
213
accessor: 'sales',
214
aggregate: 'sum', // Built-in sum aggregation
215
Aggregated: ({ value }) => `Total: ${value}`,
216
},
217
{
218
Header: 'Units',
219
accessor: 'units',
220
aggregate: (leafValues) => {
221
// Custom aggregation function
222
return leafValues.reduce((sum, val) => sum + val, 0);
223
},
224
Aggregated: ({ value }) => `${value} units`,
225
},
226
];
227
```
228
229
## Built-in Aggregation Functions
230
231
React Table provides several built-in aggregation functions:
232
233
```javascript { .api }
234
// Built-in aggregation functions
235
const aggregations = {
236
/** Sum all values */
237
sum: (leafValues: any[]) => number;
238
/** Find minimum value */
239
min: (leafValues: any[]) => number;
240
/** Find maximum value */
241
max: (leafValues: any[]) => number;
242
/** Calculate average */
243
average: (leafValues: any[]) => number;
244
/** Calculate median */
245
median: (leafValues: any[]) => number;
246
/** Get unique values as array */
247
unique: (leafValues: any[]) => any[];
248
/** Count unique values */
249
uniqueCount: (leafValues: any[]) => number;
250
/** Count all values */
251
count: (leafValues: any[]) => number;
252
/** Get min-max range as string */
253
minMax: (leafValues: any[]) => string;
254
};
255
```
256
257
## Types
258
259
```javascript { .api }
260
interface GroupByRow extends Row {
261
/** Whether this row represents a group header */
262
isGrouped: boolean;
263
/** Column ID this group is grouped by */
264
groupByID?: string;
265
/** Value this group represents */
266
groupByVal?: any;
267
/** Depth level of this group */
268
depth: number;
269
/** Leaf rows in this group */
270
leafRows?: Row[];
271
/** Sub-groups or sub-rows */
272
subRows: Row[];
273
}
274
275
interface GroupByCell extends Cell {
276
/** Whether this cell is grouped (group header cell) */
277
isGrouped: boolean;
278
/** Whether this cell shows aggregated data */
279
isAggregated: boolean;
280
/** Whether this cell is a placeholder in a grouped row */
281
isPlaceholder: boolean;
282
}
283
284
interface Column {
285
/** Aggregation function or function name */
286
aggregate?: string | ((leafValues: any[], childRows: Row[]) => any);
287
/** Component to render aggregated values */
288
Aggregated?: Renderer;
289
/** Whether this column can be grouped */
290
canGroupBy?: boolean;
291
/** Whether to disable grouping for this column */
292
disableGroupBy?: boolean;
293
}
294
```