Hooks for building lightweight, fast and extendable datagrids for React
—
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.
Enables pagination functionality with automatic page calculations and navigation methods.
/**
* Adds pagination capabilities to the table
* @param hooks - Hook registration object
*/
function usePagination(hooks: Hooks): void;
interface PaginationInstance {
/** Array of available page indices */
pageOptions: number[];
/** Total number of pages */
pageCount: number;
/** Current page of rows (subset of all rows) */
page: Row[];
/** Whether previous page is available */
canPreviousPage: boolean;
/** Whether next page is available */
canNextPage: boolean;
/** Navigate to specific page by index */
gotoPage: (pageIndex: number) => void;
/** Go to previous page */
previousPage: () => void;
/** Go to next page */
nextPage: () => void;
/** Change the number of rows per page */
setPageSize: (pageSize: number) => void;
}Configuration Options:
interface PaginationOptions {
/** Disable automatic pagination */
manualPagination?: boolean;
/** Total number of pages (for manual pagination) */
pageCount?: number;
/** Whether to include expanded rows in pagination */
paginateExpandedRows?: boolean;
/** Auto-reset to first page when data changes */
autoResetPage?: boolean;
/** Initial pagination state */
initialState?: {
pageIndex?: number;
pageSize?: number;
};
}Usage Example:
import React from 'react';
import { useTable, usePagination } from 'react-table';
function PaginatedTable({ columns, data }) {
const {
getTableProps,
getTableBodyProps,
headerGroups,
page, // Instead of 'rows', use 'page'
prepareRow,
canPreviousPage,
canNextPage,
pageOptions,
pageCount,
gotoPage,
nextPage,
previousPage,
setPageSize,
state: { pageIndex, pageSize },
} = useTable(
{
columns,
data,
initialState: { pageIndex: 0, pageSize: 10 },
},
usePagination
);
return (
<div>
<table {...getTableProps()}>
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<th {...column.getHeaderProps()}>
{column.render('Header')}
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{page.map(row => {
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => (
<td {...cell.getCellProps()}>
{cell.render('Cell')}
</td>
))}
</tr>
);
})}
</tbody>
</table>
{/* Pagination Controls */}
<div className="pagination">
<button onClick={() => gotoPage(0)} disabled={!canPreviousPage}>
{'<<'}
</button>
<button onClick={() => previousPage()} disabled={!canPreviousPage}>
{'<'}
</button>
<button onClick={() => nextPage()} disabled={!canNextPage}>
{'>'}
</button>
<button onClick={() => gotoPage(pageCount - 1)} disabled={!canNextPage}>
{'>>'}
</button>
<span>
Page{' '}
<strong>
{pageIndex + 1} of {pageOptions.length}
</strong>{' '}
</span>
<span>
| Go to page:{' '}
<input
type="number"
defaultValue={pageIndex + 1}
onChange={e => {
const page = e.target.value ? Number(e.target.value) - 1 : 0;
gotoPage(page);
}}
style={{ width: '100px' }}
/>
</span>{' '}
<select
value={pageSize}
onChange={e => {
setPageSize(Number(e.target.value));
}}
>
{[10, 20, 30, 40, 50].map(pageSize => (
<option key={pageSize} value={pageSize}>
Show {pageSize}
</option>
))}
</select>
</div>
</div>
);
}Handle pagination on the server side for large datasets that cannot be loaded entirely into memory.
function ServerPaginatedTable({ columns }) {
const [data, setData] = React.useState([]);
const [loading, setLoading] = React.useState(false);
const [pageCount, setPageCount] = React.useState(0);
const fetchData = React.useCallback(({ pageIndex, pageSize }) => {
setLoading(true);
// Fetch data from server
fetchServerData(pageIndex, pageSize).then(response => {
setData(response.data);
setPageCount(Math.ceil(response.total / pageSize));
setLoading(false);
});
}, []);
const {
getTableProps,
getTableBodyProps,
headerGroups,
page,
prepareRow,
canPreviousPage,
canNextPage,
pageOptions,
gotoPage,
nextPage,
previousPage,
setPageSize,
state: { pageIndex, pageSize },
} = useTable(
{
columns,
data,
initialState: { pageIndex: 0, pageSize: 10 },
manualPagination: true, // Tell the table we'll handle pagination
pageCount, // Pass our known page count
},
usePagination
);
// Listen for changes in pagination and use the state to fetch new data
React.useEffect(() => {
fetchData({ pageIndex, pageSize });
}, [fetchData, pageIndex, pageSize]);
return (
<div>
{loading && <div>Loading...</div>}
<table {...getTableProps()}>
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<th {...column.getHeaderProps()}>
{column.render('Header')}
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{page.map(row => {
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => (
<td {...cell.getCellProps()}>
{cell.render('Cell')}
</td>
))}
</tr>
);
})}
</tbody>
</table>
{/* Pagination controls remain the same */}
<div className="pagination">
{/* ... pagination controls ... */}
</div>
</div>
);
}Combine pagination with other table features for a complete data management solution.
import React from 'react';
import {
useTable,
useFilters,
useGlobalFilter,
useSortBy,
usePagination
} from 'react-table';
function FullFeaturedTable({ columns, data }) {
const {
getTableProps,
getTableBodyProps,
headerGroups,
page,
prepareRow,
canPreviousPage,
canNextPage,
pageOptions,
pageCount,
gotoPage,
nextPage,
previousPage,
setPageSize,
setGlobalFilter,
preGlobalFilteredRows,
state: { pageIndex, pageSize, globalFilter },
} = useTable(
{
columns,
data,
initialState: { pageIndex: 0, pageSize: 10 },
},
useFilters,
useGlobalFilter,
useSortBy,
usePagination // usePagination should be last
);
return (
<div>
{/* Global Search */}
<div>
<input
value={globalFilter || ''}
onChange={e => setGlobalFilter(e.target.value)}
placeholder="Search all columns..."
/>
</div>
<table {...getTableProps()}>
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<th {...column.getHeaderProps(column.getSortByToggleProps())}>
<div>
{column.render('Header')}
<span>
{column.isSorted
? column.isSortedDesc
? ' 🔽'
: ' 🔼'
: ''}
</span>
</div>
{/* Column Filter */}
<div>
{column.canFilter ? column.render('Filter') : null}
</div>
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{page.map(row => {
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => (
<td {...cell.getCellProps()}>
{cell.render('Cell')}
</td>
))}
</tr>
);
})}
</tbody>
</table>
{/* Pagination */}
<div className="pagination">
<button onClick={() => gotoPage(0)} disabled={!canPreviousPage}>
{'<<'}
</button>
<button onClick={() => previousPage()} disabled={!canPreviousPage}>
{'<'}
</button>
<button onClick={() => nextPage()} disabled={!canNextPage}>
{'>'}
</button>
<button onClick={() => gotoPage(pageCount - 1)} disabled={!canNextPage}>
{'>>'}
</button>
<span>
Page{' '}
<strong>
{pageIndex + 1} of {pageOptions.length}
</strong>{' '}
| Showing {page.length} of {preGlobalFilteredRows.length} results
</span>
<select
value={pageSize}
onChange={e => setPageSize(Number(e.target.value))}
>
{[10, 20, 30, 40, 50].map(pageSize => (
<option key={pageSize} value={pageSize}>
Show {pageSize}
</option>
))}
</select>
</div>
</div>
);
}Control pagination state externally for integration with routing or external state management.
function ControlledPaginationTable({ columns, data }) {
const [paginationState, setPaginationState] = React.useState({
pageIndex: 0,
pageSize: 25,
});
const {
getTableProps,
getTableBodyProps,
headerGroups,
page,
prepareRow,
pageCount,
state,
} = useTable(
{
columns,
data,
initialState: paginationState,
// Control state updates
stateReducer: (newState, action) => {
// Update external state
if (action.type.includes('page') || action.type.includes('Page')) {
setPaginationState({
pageIndex: newState.pageIndex,
pageSize: newState.pageSize,
});
}
return newState;
},
},
usePagination
);
// Sync URL with pagination state
React.useEffect(() => {
const url = new URL(window.location);
url.searchParams.set('page', (state.pageIndex + 1).toString());
url.searchParams.set('size', state.pageSize.toString());
window.history.replaceState({}, '', url);
}, [state.pageIndex, state.pageSize]);
return (
<div>
<table {...getTableProps()}>
{/* Table implementation */}
</table>
<div>
Current page: {state.pageIndex + 1} of {pageCount}
<br />
Page size: {state.pageSize}
</div>
</div>
);
}Additional pagination utilities and customization options.
interface PaginationState {
/** Current page index (0-based) */
pageIndex: number;
/** Number of rows per page */
pageSize: number;
}
interface PaginationMethods {
/** Navigate to first page */
gotoPage: (pageIndex: number) => void;
/** Go to next page if possible */
nextPage: () => void;
/** Go to previous page if possible */
previousPage: () => void;
/** Change page size and reset to first page */
setPageSize: (pageSize: number) => void;
}Custom Pagination Component:
function CustomPagination({
canPreviousPage,
canNextPage,
pageOptions,
pageCount,
gotoPage,
nextPage,
previousPage,
setPageSize,
pageIndex,
pageSize,
}) {
return (
<div className="pagination">
<div className="pagination-info">
Showing page {pageIndex + 1} of {pageCount}
</div>
<div className="pagination-buttons">
<button
onClick={() => gotoPage(0)}
disabled={!canPreviousPage}
title="First page"
>
⏮
</button>
<button
onClick={previousPage}
disabled={!canPreviousPage}
title="Previous page"
>
⏪
</button>
{/* Page number buttons */}
{pageOptions.slice(
Math.max(0, pageIndex - 2),
Math.min(pageCount, pageIndex + 3)
).map(page => (
<button
key={page}
onClick={() => gotoPage(page)}
className={pageIndex === page ? 'active' : ''}
>
{page + 1}
</button>
))}
<button
onClick={nextPage}
disabled={!canNextPage}
title="Next page"
>
⏩
</button>
<button
onClick={() => gotoPage(pageCount - 1)}
disabled={!canNextPage}
title="Last page"
>
⏭
</button>
</div>
<div className="page-size-selector">
<label>
Rows per page:
<select
value={pageSize}
onChange={e => setPageSize(Number(e.target.value))}
>
{[5, 10, 20, 30, 40, 50, 100].map(size => (
<option key={size} value={size}>
{size}
</option>
))}
</select>
</label>
</div>
</div>
);
}interface TableState {
/** Current page index (0-based) */
pageIndex: number;
/** Number of rows per page */
pageSize: number;
}
interface PaginationMeta {
instance: TableInstance;
}Install with Tessl CLI
npx tessl i tessl/npm-react-table