React hook for managing admin data table state -- pagination, sorting, searching, column visibility, localStorage persistence. Works with TanStack Query.
npm install @arraypress/data-tablePeer dependencies: react >= 18, @tanstack/react-query >= 5
A complete data table management hook. Handles pagination, sorting, searching, filtering, and column visibility with TanStack Query for caching and background refetch.
import { useDataTable } from '@arraypress/data-table';
function OrdersPage() {
const table = useDataTable({
storageKey: 'orders',
defaultSort: 'created_at',
defaultLimit: 20,
fetchFn: (params) => api.orders.list(params),
dataKey: 'orders',
filters: {
status: { initial: [] },
product: { initial: [] },
},
columns: [
{ id: 'order', label: 'Order' },
{ id: 'customer', label: 'Customer' },
{ id: 'total', label: 'Total' },
{ id: 'status', label: 'Status' },
],
defaultVisible: ['order', 'customer', 'total', 'status'],
});
if (table.loading) return <Skeleton />;
return (
<div>
<input
value={table.search}
onChange={(e) => table.handleSearch(e.target.value)}
placeholder="Search orders..."
/>
<table>
<tbody>
{table.items.map((order) => (
<tr key={order.id}>
<td>{order.id}</td>
<td>{order.customer}</td>
<td>{order.total}</td>
<td>{order.status}</td>
</tr>
))}
</tbody>
</table>
<div>
Page {table.page} of {table.pages} ({table.total} total)
<button onClick={() => table.handlePageChange(table.page - 1)} disabled={table.page <= 1}>
Previous
</button>
<button onClick={() => table.handlePageChange(table.page + 1)} disabled={table.page >= table.pages}>
Next
</button>
</div>
</div>
);
}| Option | Type | Default | Description |
|---|---|---|---|
storageKey |
string |
— | Key for localStorage persistence + TanStack Query prefix. |
defaultSort |
string |
'created_at' |
Default sort column. |
defaultOrder |
'asc' | 'desc' |
'desc' |
Default sort direction. |
defaultLimit |
number |
20 |
Default items per page (10, 20, 50, or 100). |
fetchFn |
(params) => Promise |
— | API fetch function receiving query params. |
dataKey |
string |
— | Key in API response containing the data array. |
filters |
Record<string, { initial: any[] }> |
{} |
Filter configuration. |
columns |
{ id: string, label: string }[] |
[] |
Column definitions. |
defaultVisible |
string[] |
all columns | Initially visible column IDs. |
| Property | Type | Description |
|---|---|---|
items |
any[] |
Current page data. |
total |
number |
Total items across all pages. |
loading |
boolean |
Initial load in progress. |
fetching |
boolean |
Background refetch in progress. |
page |
number |
Current page (1-based). |
pages |
number |
Total pages. |
limit |
number |
Items per page. |
handlePageChange |
(page) => void |
Navigate to page. |
handleLimitChange |
(limit) => void |
Change page size. |
search |
string |
Current search string. |
handleSearch |
(value) => void |
Update search (resets to page 1). |
sort |
string |
Current sort column. |
order |
string |
Current sort direction. |
handleSort |
(col, ord) => void |
Update sort (resets to page 1). |
filters |
Record<string, any[]> |
Current filter values. |
handleFilter |
(key, values) => void |
Update filter (resets to page 1). |
isFiltered |
boolean |
Whether any filter/search is active. |
resetFilters |
() => void |
Clear all filters and search. |
columns |
ColumnDef[] |
Column definitions. |
visibleColumns |
string[] |
Currently visible column IDs. |
toggleColumn |
(id) => void |
Toggle column visibility. |
refresh |
() => void |
Invalidate cache and refetch. |
rawData |
any |
Full API response (for extra fields). |
Pure function to build query parameters from table state. Useful for testing or custom implementations.
import { buildQueryParams } from '@arraypress/data-table';
buildQueryParams({
page: 1, limit: 20, search: 'test', sort: 'name', order: 'asc',
filterKeys: ['status'], filterState: { status: ['active'] },
});
// => { page: 1, limit: 20, search: 'test', sort: 'name', order: 'asc', status: 'active' }Array of valid page size options: [10, 20, 50, 100].
The fetchFn should return an object with:
{
[dataKey]: [...], // Array of items
total: 100, // Total item count
pages: 5, // Optional — calculated from total/limit if not provided
}MIT