0
# Pagination
1
2
React Table provides built-in pagination functionality that handles large datasets efficiently. The pagination system supports both client-side and server-side pagination with intuitive navigation controls and configurable page sizes.
3
4
## Capabilities
5
6
### usePagination Hook
7
8
Enables pagination functionality with automatic page calculations and navigation methods.
9
10
```javascript { .api }
11
/**
12
* Adds pagination capabilities to the table
13
* @param hooks - Hook registration object
14
*/
15
function usePagination(hooks: Hooks): void;
16
17
interface PaginationInstance {
18
/** Array of available page indices */
19
pageOptions: number[];
20
/** Total number of pages */
21
pageCount: number;
22
/** Current page of rows (subset of all rows) */
23
page: Row[];
24
/** Whether previous page is available */
25
canPreviousPage: boolean;
26
/** Whether next page is available */
27
canNextPage: boolean;
28
/** Navigate to specific page by index */
29
gotoPage: (pageIndex: number) => void;
30
/** Go to previous page */
31
previousPage: () => void;
32
/** Go to next page */
33
nextPage: () => void;
34
/** Change the number of rows per page */
35
setPageSize: (pageSize: number) => void;
36
}
37
```
38
39
**Configuration Options:**
40
41
```javascript { .api }
42
interface PaginationOptions {
43
/** Disable automatic pagination */
44
manualPagination?: boolean;
45
/** Total number of pages (for manual pagination) */
46
pageCount?: number;
47
/** Whether to include expanded rows in pagination */
48
paginateExpandedRows?: boolean;
49
/** Auto-reset to first page when data changes */
50
autoResetPage?: boolean;
51
/** Initial pagination state */
52
initialState?: {
53
pageIndex?: number;
54
pageSize?: number;
55
};
56
}
57
```
58
59
**Usage Example:**
60
61
```javascript
62
import React from 'react';
63
import { useTable, usePagination } from 'react-table';
64
65
function PaginatedTable({ columns, data }) {
66
const {
67
getTableProps,
68
getTableBodyProps,
69
headerGroups,
70
page, // Instead of 'rows', use 'page'
71
prepareRow,
72
canPreviousPage,
73
canNextPage,
74
pageOptions,
75
pageCount,
76
gotoPage,
77
nextPage,
78
previousPage,
79
setPageSize,
80
state: { pageIndex, pageSize },
81
} = useTable(
82
{
83
columns,
84
data,
85
initialState: { pageIndex: 0, pageSize: 10 },
86
},
87
usePagination
88
);
89
90
return (
91
<div>
92
<table {...getTableProps()}>
93
<thead>
94
{headerGroups.map(headerGroup => (
95
<tr {...headerGroup.getHeaderGroupProps()}>
96
{headerGroup.headers.map(column => (
97
<th {...column.getHeaderProps()}>
98
{column.render('Header')}
99
</th>
100
))}
101
</tr>
102
))}
103
</thead>
104
<tbody {...getTableBodyProps()}>
105
{page.map(row => {
106
prepareRow(row);
107
return (
108
<tr {...row.getRowProps()}>
109
{row.cells.map(cell => (
110
<td {...cell.getCellProps()}>
111
{cell.render('Cell')}
112
</td>
113
))}
114
</tr>
115
);
116
})}
117
</tbody>
118
</table>
119
120
{/* Pagination Controls */}
121
<div className="pagination">
122
<button onClick={() => gotoPage(0)} disabled={!canPreviousPage}>
123
{'<<'}
124
</button>
125
<button onClick={() => previousPage()} disabled={!canPreviousPage}>
126
{'<'}
127
</button>
128
<button onClick={() => nextPage()} disabled={!canNextPage}>
129
{'>'}
130
</button>
131
<button onClick={() => gotoPage(pageCount - 1)} disabled={!canNextPage}>
132
{'>>'}
133
</button>
134
<span>
135
Page{' '}
136
<strong>
137
{pageIndex + 1} of {pageOptions.length}
138
</strong>{' '}
139
</span>
140
<span>
141
| Go to page:{' '}
142
<input
143
type="number"
144
defaultValue={pageIndex + 1}
145
onChange={e => {
146
const page = e.target.value ? Number(e.target.value) - 1 : 0;
147
gotoPage(page);
148
}}
149
style={{ width: '100px' }}
150
/>
151
</span>{' '}
152
<select
153
value={pageSize}
154
onChange={e => {
155
setPageSize(Number(e.target.value));
156
}}
157
>
158
{[10, 20, 30, 40, 50].map(pageSize => (
159
<option key={pageSize} value={pageSize}>
160
Show {pageSize}
161
</option>
162
))}
163
</select>
164
</div>
165
</div>
166
);
167
}
168
```
169
170
### Server-Side Pagination
171
172
Handle pagination on the server side for large datasets that cannot be loaded entirely into memory.
173
174
```javascript
175
function ServerPaginatedTable({ columns }) {
176
const [data, setData] = React.useState([]);
177
const [loading, setLoading] = React.useState(false);
178
const [pageCount, setPageCount] = React.useState(0);
179
180
const fetchData = React.useCallback(({ pageIndex, pageSize }) => {
181
setLoading(true);
182
// Fetch data from server
183
fetchServerData(pageIndex, pageSize).then(response => {
184
setData(response.data);
185
setPageCount(Math.ceil(response.total / pageSize));
186
setLoading(false);
187
});
188
}, []);
189
190
const {
191
getTableProps,
192
getTableBodyProps,
193
headerGroups,
194
page,
195
prepareRow,
196
canPreviousPage,
197
canNextPage,
198
pageOptions,
199
gotoPage,
200
nextPage,
201
previousPage,
202
setPageSize,
203
state: { pageIndex, pageSize },
204
} = useTable(
205
{
206
columns,
207
data,
208
initialState: { pageIndex: 0, pageSize: 10 },
209
manualPagination: true, // Tell the table we'll handle pagination
210
pageCount, // Pass our known page count
211
},
212
usePagination
213
);
214
215
// Listen for changes in pagination and use the state to fetch new data
216
React.useEffect(() => {
217
fetchData({ pageIndex, pageSize });
218
}, [fetchData, pageIndex, pageSize]);
219
220
return (
221
<div>
222
{loading && <div>Loading...</div>}
223
224
<table {...getTableProps()}>
225
<thead>
226
{headerGroups.map(headerGroup => (
227
<tr {...headerGroup.getHeaderGroupProps()}>
228
{headerGroup.headers.map(column => (
229
<th {...column.getHeaderProps()}>
230
{column.render('Header')}
231
</th>
232
))}
233
</tr>
234
))}
235
</thead>
236
<tbody {...getTableBodyProps()}>
237
{page.map(row => {
238
prepareRow(row);
239
return (
240
<tr {...row.getRowProps()}>
241
{row.cells.map(cell => (
242
<td {...cell.getCellProps()}>
243
{cell.render('Cell')}
244
</td>
245
))}
246
</tr>
247
);
248
})}
249
</tbody>
250
</table>
251
252
{/* Pagination controls remain the same */}
253
<div className="pagination">
254
{/* ... pagination controls ... */}
255
</div>
256
</div>
257
);
258
}
259
```
260
261
### Pagination with Filtering and Sorting
262
263
Combine pagination with other table features for a complete data management solution.
264
265
```javascript
266
import React from 'react';
267
import {
268
useTable,
269
useFilters,
270
useGlobalFilter,
271
useSortBy,
272
usePagination
273
} from 'react-table';
274
275
function FullFeaturedTable({ columns, data }) {
276
const {
277
getTableProps,
278
getTableBodyProps,
279
headerGroups,
280
page,
281
prepareRow,
282
canPreviousPage,
283
canNextPage,
284
pageOptions,
285
pageCount,
286
gotoPage,
287
nextPage,
288
previousPage,
289
setPageSize,
290
setGlobalFilter,
291
preGlobalFilteredRows,
292
state: { pageIndex, pageSize, globalFilter },
293
} = useTable(
294
{
295
columns,
296
data,
297
initialState: { pageIndex: 0, pageSize: 10 },
298
},
299
useFilters,
300
useGlobalFilter,
301
useSortBy,
302
usePagination // usePagination should be last
303
);
304
305
return (
306
<div>
307
{/* Global Search */}
308
<div>
309
<input
310
value={globalFilter || ''}
311
onChange={e => setGlobalFilter(e.target.value)}
312
placeholder="Search all columns..."
313
/>
314
</div>
315
316
<table {...getTableProps()}>
317
<thead>
318
{headerGroups.map(headerGroup => (
319
<tr {...headerGroup.getHeaderGroupProps()}>
320
{headerGroup.headers.map(column => (
321
<th {...column.getHeaderProps(column.getSortByToggleProps())}>
322
<div>
323
{column.render('Header')}
324
<span>
325
{column.isSorted
326
? column.isSortedDesc
327
? ' 🔽'
328
: ' 🔼'
329
: ''}
330
</span>
331
</div>
332
{/* Column Filter */}
333
<div>
334
{column.canFilter ? column.render('Filter') : null}
335
</div>
336
</th>
337
))}
338
</tr>
339
))}
340
</thead>
341
<tbody {...getTableBodyProps()}>
342
{page.map(row => {
343
prepareRow(row);
344
return (
345
<tr {...row.getRowProps()}>
346
{row.cells.map(cell => (
347
<td {...cell.getCellProps()}>
348
{cell.render('Cell')}
349
</td>
350
))}
351
</tr>
352
);
353
})}
354
</tbody>
355
</table>
356
357
{/* Pagination */}
358
<div className="pagination">
359
<button onClick={() => gotoPage(0)} disabled={!canPreviousPage}>
360
{'<<'}
361
</button>
362
<button onClick={() => previousPage()} disabled={!canPreviousPage}>
363
{'<'}
364
</button>
365
<button onClick={() => nextPage()} disabled={!canNextPage}>
366
{'>'}
367
</button>
368
<button onClick={() => gotoPage(pageCount - 1)} disabled={!canNextPage}>
369
{'>>'}
370
</button>
371
<span>
372
Page{' '}
373
<strong>
374
{pageIndex + 1} of {pageOptions.length}
375
</strong>{' '}
376
| Showing {page.length} of {preGlobalFilteredRows.length} results
377
</span>
378
<select
379
value={pageSize}
380
onChange={e => setPageSize(Number(e.target.value))}
381
>
382
{[10, 20, 30, 40, 50].map(pageSize => (
383
<option key={pageSize} value={pageSize}>
384
Show {pageSize}
385
</option>
386
))}
387
</select>
388
</div>
389
</div>
390
);
391
}
392
```
393
394
### Pagination State Management
395
396
Control pagination state externally for integration with routing or external state management.
397
398
```javascript
399
function ControlledPaginationTable({ columns, data }) {
400
const [paginationState, setPaginationState] = React.useState({
401
pageIndex: 0,
402
pageSize: 25,
403
});
404
405
const {
406
getTableProps,
407
getTableBodyProps,
408
headerGroups,
409
page,
410
prepareRow,
411
pageCount,
412
state,
413
} = useTable(
414
{
415
columns,
416
data,
417
initialState: paginationState,
418
// Control state updates
419
stateReducer: (newState, action) => {
420
// Update external state
421
if (action.type.includes('page') || action.type.includes('Page')) {
422
setPaginationState({
423
pageIndex: newState.pageIndex,
424
pageSize: newState.pageSize,
425
});
426
}
427
return newState;
428
},
429
},
430
usePagination
431
);
432
433
// Sync URL with pagination state
434
React.useEffect(() => {
435
const url = new URL(window.location);
436
url.searchParams.set('page', (state.pageIndex + 1).toString());
437
url.searchParams.set('size', state.pageSize.toString());
438
window.history.replaceState({}, '', url);
439
}, [state.pageIndex, state.pageSize]);
440
441
return (
442
<div>
443
<table {...getTableProps()}>
444
{/* Table implementation */}
445
</table>
446
447
<div>
448
Current page: {state.pageIndex + 1} of {pageCount}
449
<br />
450
Page size: {state.pageSize}
451
</div>
452
</div>
453
);
454
}
455
```
456
457
### Advanced Pagination Features
458
459
Additional pagination utilities and customization options.
460
461
```javascript { .api }
462
interface PaginationState {
463
/** Current page index (0-based) */
464
pageIndex: number;
465
/** Number of rows per page */
466
pageSize: number;
467
}
468
469
interface PaginationMethods {
470
/** Navigate to first page */
471
gotoPage: (pageIndex: number) => void;
472
/** Go to next page if possible */
473
nextPage: () => void;
474
/** Go to previous page if possible */
475
previousPage: () => void;
476
/** Change page size and reset to first page */
477
setPageSize: (pageSize: number) => void;
478
}
479
```
480
481
**Custom Pagination Component:**
482
483
```javascript
484
function CustomPagination({
485
canPreviousPage,
486
canNextPage,
487
pageOptions,
488
pageCount,
489
gotoPage,
490
nextPage,
491
previousPage,
492
setPageSize,
493
pageIndex,
494
pageSize,
495
}) {
496
return (
497
<div className="pagination">
498
<div className="pagination-info">
499
Showing page {pageIndex + 1} of {pageCount}
500
</div>
501
502
<div className="pagination-buttons">
503
<button
504
onClick={() => gotoPage(0)}
505
disabled={!canPreviousPage}
506
title="First page"
507
>
508
⏮
509
</button>
510
<button
511
onClick={previousPage}
512
disabled={!canPreviousPage}
513
title="Previous page"
514
>
515
⏪
516
</button>
517
518
{/* Page number buttons */}
519
{pageOptions.slice(
520
Math.max(0, pageIndex - 2),
521
Math.min(pageCount, pageIndex + 3)
522
).map(page => (
523
<button
524
key={page}
525
onClick={() => gotoPage(page)}
526
className={pageIndex === page ? 'active' : ''}
527
>
528
{page + 1}
529
</button>
530
))}
531
532
<button
533
onClick={nextPage}
534
disabled={!canNextPage}
535
title="Next page"
536
>
537
⏩
538
</button>
539
<button
540
onClick={() => gotoPage(pageCount - 1)}
541
disabled={!canNextPage}
542
title="Last page"
543
>
544
⏭
545
</button>
546
</div>
547
548
<div className="page-size-selector">
549
<label>
550
Rows per page:
551
<select
552
value={pageSize}
553
onChange={e => setPageSize(Number(e.target.value))}
554
>
555
{[5, 10, 20, 30, 40, 50, 100].map(size => (
556
<option key={size} value={size}>
557
{size}
558
</option>
559
))}
560
</select>
561
</label>
562
</div>
563
</div>
564
);
565
}
566
```
567
568
## Types
569
570
```javascript { .api }
571
interface TableState {
572
/** Current page index (0-based) */
573
pageIndex: number;
574
/** Number of rows per page */
575
pageSize: number;
576
}
577
578
interface PaginationMeta {
579
instance: TableInstance;
580
}
581
```