Skip to content

Repository files navigation

kvant

Universal, type-safe state manager for key‑value interfaces:
URL search params, cookies, localStorage, sessionStorage, and more.

npm Version React Vue npm License


Installation

Install kvant with your package manager of choice:

npm install kvantjs
pnpm add kvantjs
yarn add kvantjs
bun add kvantjs

Documentation

Read the complete documentation for your framework of choice:

Quick Start

Tip

Below you'll find a quick start guide based on Next.js (app router).

For complete docs on Next.js and other frameworks, please see the options above.

kvant turns key-value interfaces into React state. Bind a key, pass a schema from kvantjs/schema, and read/write it like useState. The interface (here, the URL) stays the single source of truth:

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

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

  return (
    <input
      value={query}
      onChange={e => setQuery(e.target.value)}
    />
  )
}

?q=hello in the URL means query is 'hello'. Calling setQuery writes back to the URL.

Multiple keys

Bind a whole key map in one call. Updates batch into a single write:

const [filters, setFilters] = useSearchParams({
  q: kv.string().default(''),
  page: kv.index().default(0),
  sort: kv.enum(['asc', 'desc']).default('asc'),
  tags: kv.array(kv.string()).default([]), // repeated params: ?tags=a&tags=b
})

setFilters(prev => ({ ...prev, page: prev.page + 1 }))

Options

Pass options as the last argument:

const [query, setQuery] = useSearchParams('q', kv.string().default(''), {
  history: 'push', // add browser history entries
  shallow: false, // go through the Next.js router (re-run server components)
})

Global default options

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

import { SearchParamsOptionsProvider } from 'kvantjs/next'

<SearchParamsOptionsProvider defaultOptions={{ history: 'push' }}>
  {children}
</SearchParamsOptionsProvider>

Every interface

The same pattern works for all supported key-value interfaces:

import { useSearchParams } from 'kvantjs/next'
import { useCookies, useLocalStorage, useSessionStorage } from 'kvantjs/react'
import * as kv from 'kvantjs/schema'

// URL search params: shareable, bookmarkable
const [query, setQuery] = useSearchParams('q', kv.string().default(''))

// localStorage: persists across reloads, syncs across tabs
const [theme, setTheme] = useLocalStorage('theme', kv.enum(['light', 'dark']).default('light'))

// sessionStorage: scoped to the current tab
const [draft, setDraft] = useSessionStorage('draft', kv.string().default(''))

// Cookies: readable by the server, respect Set-Cookie attributes
// (requires additional setup for SSR, see the full guide)
const [consent, setConsent] = useCookies(
  'consent',
  kv.stringbool().default(false),
  { maxAge: 60 * 60 * 24 * 365 },
)

Full guides: Search Params · Local Storage · Cookies

Special Thanks

  • nuqs 🖤 played a marginal role in inspiring the kvant API, as well as providing bits and pieces of code for the kvant internals.
  • kvant API is shaped around zod 💙 as kvantjs/schema builds on your existing Zod intuition, so defining schemas feels just like writing plain Zod.

License

MIT License © Oleg Kapranov

About

Universal, type-safe state manager for key-value interfaces

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages