tanstack-router-persist-search
v0.3.0
Published
Persist and restore TanStack Router search params per route via sessionStorage/localStorage
Maintainers
Readme
tanstack-router-persist-search
Remembers search params of a TanStack Router route and restores them when the user comes back to it.
Typical case: a list page with filters and pagination. The user sets ?page=3&status=active, opens an item, then clicks "Users" in the menu. Without this package they land on page 1 with no filters. With it, they are redirected back to ?page=3&status=active.
- Zero dependencies (only
@tanstack/react-routeras a peer) sessionStorageby default, anyStoragevia options- SSR-safe: does nothing when storage is unavailable
- ~1 KB
Install
npm i tanstack-router-persist-searchUsage
import { createFileRoute } from '@tanstack/react-router'
import { persistSearch } from 'tanstack-router-persist-search'
export const Route = createFileRoute('/users')({
beforeLoad: persistSearch,
})The route id is taken from the beforeLoad context (ctx.routeId), so you don't pass it yourself.
With options, or together with other logic in beforeLoad:
beforeLoad: (ctx) => {
persistSearch(ctx, { include: ['page', 'status'] })
// ...the rest
},
persistSearchmay throw aredirect, so code after it won't run in that case. Put anything that must always run before the call.
How it works
"Empty" below means no tracked params (see include/exclude); without options every param is tracked.
| cause | Search is empty | Search is not empty |
| --------- | -------------------------- | ------------------- |
| enter | redirect to saved search (if any) | save it |
| stay | remove saved entry | save it |
| preload | ignored | ignored |
- Keys with
undefinedvalues are dropped before saving and when checking for emptiness, so{ page: undefined }counts as empty. - The redirect uses
replace: true, so no extra history entry is created. - Each route is stored separately under its route id (e.g.
/users,/_layout/users/). - To share saved params between several routes, give them the same slot:
persistSearch(ctx, { routeId: 'users-filters' }).
Persist only some params
Pass include or exclude as the second argument:
// save and restore only pagination and filters
beforeLoad: (ctx) => persistSearch(ctx, { include: ['page', 'status'] }),
// save everything except one-off params
beforeLoad: (ctx) => persistSearch(ctx, { exclude: ['token', 'highlight'] }),- Keys are type-checked against the route's
validateSearch, with autocomplete. On routes withoutvalidateSearchany string is accepted. - If both are given,
includeis applied first, thenexclude. - Only tracked params count when deciding whether to restore. Entering
/users?tab=infowithinclude: ['page', 'status']redirects to/users?tab=info&page=3&status=active: untracked params from the URL are kept and saved ones are added. - If any tracked param is already in the URL, nothing is restored; the URL wins and is saved.
- Saved data is filtered with the current options on restore, so changing
include/excludelater never brings back a param you stopped tracking.
Custom storage
import { createSearchPersistence } from 'tanstack-router-persist-search'
export const filters = createSearchPersistence({
key: 'my-app:search', // default: 'search-storage'
storage: () => localStorage, // default: sessionStorage
})
// in a route
beforeLoad: filters.persistSearch,API
createSearchPersistence(options?)
| Option | Type | Default |
| --------- | ------------------------------- | ------------------ |
| key | string | 'search-storage' |
| storage | () => Storage \| undefined | sessionStorage (undefined on the server) |
Returns:
persistSearch(ctx, options?)— use inbeforeLoad;optionsis{ include?, exclude?, routeId? }.routeIddefaults toctx.routeId; if neither is available, it throws an error.get(routeId)— saved search orundefinedsave(routeId, search, options?)— save manually, with the same filteringclear(routeId?)— clear one route, or everything when called without arguments
Default instance exports
persistSearch, getPersistedSearch, savePersistedSearch, clearPersistedSearch — the same functions bound to sessionStorage and the 'search-storage' key.
Example: a "Reset filters" button
clearPersistedSearch('/users')
navigate({ to: '/users', search: {} })Requirements
@tanstack/react-router1.x- TypeScript 5.4+ (the types use
NoInfer)
License
MIT
