useDataTableSearchParams
Sync TanStack Table V9 state through route-owned, validated TanStack Router search params.
Installation
npx shadcn@latest add @redpanda/use-data-table-search-paramspnpm dlx shadcn@latest add @redpanda/use-data-table-search-paramsyarn dlx shadcn@latest add @redpanda/use-data-table-search-paramsbunx shadcn@latest add @redpanda/use-data-table-search-paramsnubx shadcn@latest add @redpanda/use-data-table-search-paramsaube dlx shadcn@latest add @redpanda/use-data-table-search-paramsuseDataTableSearchParams maps pagination, sorting, optional column filters, and optional global search to shareable URL state. The route validates search params; a provider adapts the typed route hooks to the reusable registry hook. Navigation merges previous search state and uses replace: true.
Route setup
import { createRoute } from "@tanstack/react-router"
import {
DataTableSearchParamsProvider,
validateDataTableSearchParams,
} from "@/hooks/use-data-table-search-params"
export const usersRoute = createRoute({
getParentRoute: () => rootRoute,
path: "/users",
validateSearch: validateDataTableSearchParams,
component: UsersRoute,
})
function UsersRoute() {
const search = usersRoute.useSearch()
const navigate = usersRoute.useNavigate()
return (
<DataTableSearchParamsProvider search={search} navigate={navigate}>
<UsersTable />
</DataTableSearchParamsProvider>
)
}
Keep validateSearch on the route that owns the table. Use that route’s useSearch and useNavigate helpers so TanStack Router infers types without casts or strict: false access.
Table setup
import { DataTable } from "@/components/redpanda-ui/data-table"
import { useDataTableSearchParams } from "@/hooks/use-data-table-search-params"
function UsersTable() {
const {
pagination,
onPaginationChange,
sorting,
onSortingChange,
globalFilter,
onGlobalFilterChange,
} = useDataTableSearchParams({ syncGlobalFilter: true })
return (
<DataTable
columns={columns}
data={data}
tableOptions={{
state: { pagination, sorting, globalFilter },
onPaginationChange,
onSortingChange,
onGlobalFilterChange,
}}
/>
)
}
Multiple tables
Prefix keys when several tables share a route.
import { createDataTableSearchParamsValidator } from "@/hooks/use-data-table-search-params"
const validateSearch = createDataTableSearchParamsValidator({
prefixes: ["users", "teams"],
})
const usersState = useDataTableSearchParams({ paramPrefix: "users" })
const teamsState = useDataTableSearchParams({ paramPrefix: "teams" })
This produces keys such as users_page, users_pageSize, users_globalFilter, and teams_sort. Declare every prefix in the route validator so similarly named, unrelated route params remain untouched.
First-page resets
Sorting, column-filter, global-filter, and page-size changes reset pagination to page 1 by default. The reset is merged into the same TanStack Router navigation, so the URL never exposes a transient stale page. Set resetPageOnStateChange: false only when the backing data source deliberately preserves page position.
API
validateDataTableSearchParams(search)
Use as TanStack Router’s validateSearch. It normalizes positive page values, validates column.direction sorting segments, filter JSON, and string global filters, rejects malformed table state, and preserves unrelated route search params.
createDataTableSearchParamsValidator({ prefixes })
Create a validateSearch function for routes with prefixed table state. Only unprefixed table keys and keys matching the declared prefixes are validated; all other search params pass through unchanged.
DataTableSearchParamsProvider
| Prop | Type | Description |
|---|---|---|
search |
DataTableSearchParams |
Value returned by the owning route’s useSearch. |
navigate |
DataTableSearchParamsNavigate |
Typed adapter around the owning route’s useNavigate. |
children |
ReactNode |
Tables that consume URL state. |
useDataTableSearchParams(options?)
| Option | Type | Default | Description |
|---|---|---|---|
syncPagination |
boolean |
true |
Sync pagination. |
syncSorting |
boolean |
true |
Sync sorting. |
syncFilters |
boolean |
false |
Sync column filters. |
syncGlobalFilter |
boolean |
false |
Sync the V9 global-filter slice. |
paramPrefix |
string |
— | Namespace keys for one table. |
defaultPagination |
PaginationState |
{ pageIndex: 0, pageSize: 10 } |
State used when the URL omits pagination. |
defaultSorting |
SortingState |
[] |
State used when the URL omits sorting. |
defaultGlobalFilter |
string |
"" |
State used when the URL omits global search. |
resetPageOnStateChange |
boolean |
true |
Reset to page 1 atomically when sorting, filtering, global search, or page size changes. |
Returns TanStack Table-compatible state slices and onChange handlers. Pass them through DataTable’s tableOptions.
Related
For token APIs that cannot express offsets, use useTokenPagination.