Search Params

Bind React state to URL search params in the Next.js app router.

useSearchParams binds state to URL search params. The URL is the single source of truth: refreshing, sharing, or bookmarking the link restores the exact state. Writes use the native History API by default (shallow), so no server round-trip happens, and updates are applied optimistically inside a React transition.

import {  } from 'kvantjs/next'
import * as  from 'kvantjs/schema'

function () {
  const [, ] = ('q', .().(''))

  return (
    <
      ={}
      ={ => (..)}
    />
  )
}

Setting a key to undefined removes its entry. Values equal to the schema default are never written. Defaults stay internal. Multiple hooks bound to the same key stay in sync automatically.

Key maps work too:

const [, ] = ({
  : .().(''),
  : .().(0),
  : .(['asc', 'desc']).('asc'),
  : .(.()).([]), // repeated params: ?tags=a&tags=b
})

( => ({ ..., : . + 1 }))

Fast-changing values

kvant does not yet provide built-in throttle/debounce for URL writes. Until then, avoid binding state directly to quickly changing values (text inputs, sliders), or wrap the binding in a throttled layer with local state:

import { useThrottleFn } from 'react-use'

function SearchInput() {
  const [search, setSearch] = useSearchParams('q', kv.string().default(''))

  // Local state updates instantly; the URL follows at most every 300 ms
  const [text, setText] = useState(search)
  useThrottleFn(setSearch, 300, [text])

  return <input value={text} onChange={e => setText(e.target.value)} />
}

Options

Prop

Type

Set options once for a component subtree using the options provider:

import {  } from 'kvantjs/next'

< ={{ : 'push' }}>
  {}
</>

Custom search serializer

The default serializer uses URLSearchParams, so values are flat strings (or repeated keys for arrays). For nested structures, plug in a custom parser/serializer, for example qs, by defining your own binding (see Advanced Usage):

lib/search-params.ts
'use client'
import {  } from 'kvantjs/next'
import {  } from 'kvantjs/react'
import qs from 'qs'

export const {
  : ,
  : 
} = (
  (, ) => (, {
    :  => qs.(, { : true }),
    :  => qs.(, { : true }),
    ...,
  }),
)

With qs handling (de)serialization, the full power of kvantjs/schema opens up inside the URL: objects, nested arrays, and more.

const [, ] = (
  'filters',
  .({
    : .(.()).([]),
    : .([.(), .()]).(),
  }).({}),
)
// URL: ?filters[tags][0]=a&filters[tags][1]=b&filters[range][0]=1&filters[range][1]=9

On this page