Skip to content

Releases: seasonedcc/preserve-search-params

preserve-search-params@0.1.0

Choose a tag to compare

Initial public release of preserve-search-params — a zero-dependency, framework-agnostic primitive for preserving URL search params across navigations and form submissions.

What's included

preserveSearchParams(search, options?)

Takes a URLSearchParams, returns a new URLSearchParams. Sync, pure, no I/O.

  • Preserve everything (default)
  • Drop everything (preserve: []) — for reset links
  • Allow-list specific params (preserve: ['page', 'q'])
  • Set, override, or clear values via customValues (passing null clears)

redirectPathWithSearchParams(request, path, options?)

Builds a redirect destination string from a Request and a target path. Preserves the request's search params and merges any params already on the target path. Setting customValues[key] = null clears.

const dest = redirectPathWithSearchParams(request, '/items/123#header', {
  customValues: { tab: 'observations' },
})
// → /items/123?page=2&filter=active&tab=observations#header

serializeToSearchParams(params, value, prefix)

The lower-level utility behind customValues. Mutates params in place, appending under prefix with recursive bracket notation.

Recursive customValues serialization

  • Arrays of primitives: tags[]=urgent&tags[]=review
  • Arrays of objects: users[0][name]=Alice&users[1][name]=Bob
  • Nested arrays under bracketed prefix: filter[scores][0]=1
  • null removes a key (or whole subtree)

Install

pnpm add preserve-search-params

Adapters

Most apps want a framework adapter built on top of this:

What's Changed

Full Changelog: https://github.com/seasonedcc/preserve-search-params/commits/preserve-search-params@0.1.0

@preserve-search-params/react-router@0.1.0

Choose a tag to compare

Initial public release of @preserve-search-params/react-router — the React Router v7+ adapter for preserve-search-params.

The wrappers read the current location automatically with useLocation(), so you don't have to thread the URL through your component tree.

What's included

<SearchParamsLink>

Wraps Link from react-router. Preserves params by default; opt out with preserve={[]} or override with customValues.

// On /items?page=2&filter=active
<SearchParamsLink to="/items/123">Open</SearchParamsLink>
// → /items/123?page=2&filter=active

Polymorphic via the component prop — pass any custom Link component and its required/optional props are inferred at the call site.

<SearchParamsForm>

GET-method form wrapper. Renders one hidden <input> per preserved param. Polymorphic via component (use component={fetcher.Form} for fetcher submissions).

useResolvedPathWithSearchParams(to, options?)

Wraps RR's useResolvedPath and replaces the search portion with the preserved query string. Returns a Path for useNavigate() and any RR primitive that takes a Path.

redirectPathWithSearchParams(request, path, options?)

Server-side redirect helper for loaders and actions. Preserves the request's search params and merges any params already on the target path.

export async function action({ request }: ActionFunctionArgs) {
  // ... mutation
  return redirect(
    redirectPathWithSearchParams(request, '/items', {
      customValues: { page: null },
    })
  )
}

Re-exports

preserveSearchParams, serializeToSearchParams, and all related types from the core package are re-exported, so the adapter is the only dependency you need to import from.

Peer dependencies

  • react >=19
  • react-router >=7

Install

pnpm add @preserve-search-params/react-router

What's Changed

  • Add release skill adapted to Changesets monorepo by @danielweinmann in #1
  • Add redirectPathWithSearchParams helper and broaden type exports by @danielweinmann in #2
  • Bump react peer dep to >=19, make RR SearchParamsForm polymorphic by @danielweinmann in #3

Full Changelog: https://github.com/seasonedcc/preserve-search-params/commits/@preserve-search-params/react-router@0.1.0

@preserve-search-params/next@0.1.0

Choose a tag to compare

Initial public release of @preserve-search-params/next — the Next.js adapter for preserve-search-params, supporting both App Router and Pages Router.

The components are pure (no 'use client') and accept the current URL's search params as a prop. The same component works in App Router server components, App Router client components, and Pages Router pages — you read the URL once per page in whichever way fits, and pass the result down.

What's included

<SearchParamsLink>

Wraps next/link. Computes the destination href with preservation rules applied to currentSearchParams.

// current = new URLSearchParams('page=2&filter=active')
<SearchParamsLink href="/items/123" currentSearchParams={current}>
  Open
</SearchParamsLink>
// → /items/123?page=2&filter=active

Polymorphic via the component prop — pass any custom Link component and its required/optional props are inferred at the call site.

<SearchParamsForm>

GET-method form wrapper. Renders one hidden <input> per preserved param. Polymorphic via component — pass next/form's Form to opt into Next 15+'s prefetch-on-hover/focus for the form's GET target.

redirectPathWithSearchParams(request, path, options?)

Server-side redirect helper for App Router server actions and Pages Router getServerSideProps. In Server Actions where the current URL isn't part of the call, build a Request from the referer header:

'use server'
import { headers } from 'next/headers'
import { redirect } from 'next/navigation'
import { redirectPathWithSearchParams } from '@preserve-search-params/next'

export async function archiveItem(id: string) {
  // ... mutation
  const referer = (await headers()).get('referer') ?? 'http://x/'
  redirect(
    redirectPathWithSearchParams(new Request(referer), '/items', {
      customValues: { page: null },
    })
  )
}

Re-exports

preserveSearchParams, serializeToSearchParams, and all related types from the core package are re-exported, so the adapter is the only dependency you need to import from.

Peer dependencies

  • react >=19
  • next >=14

Install

pnpm add @preserve-search-params/next

What's Changed

  • Add release skill adapted to Changesets monorepo by @danielweinmann in #1
  • Add redirectPathWithSearchParams helper and broaden type exports by @danielweinmann in #2
  • Bump react peer dep to >=19, make RR SearchParamsForm polymorphic by @danielweinmann in #3

Full Changelog: https://github.com/seasonedcc/preserve-search-params/commits/@preserve-search-params/next@0.1.0