šŸ“ Sign Up | šŸ” Log In

← Root | ↑ Up

ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā” │ šŸ“„ shadcn/directory/47ng/nuqs/adapters │ ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

╔══════════════════════════════════════════════════════════════════════════════════════════════╗
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘

title: Adapters description: Using nuqs in your React framework of choice

import { NextJS, ReactRouter, ReactRouterV7, ReactSPA, Remix, TanStackRouter, Vitest, } from '@/src/components/frameworks'

Since version 2, you can now use nuqs in the following React frameworks, by wrapping it with a NuqsAdapter{:ts} context provider:

<NextJS className='inline mr-1.5 -mt-1' role="presentation" /> Next.js [#nextjs]

App router [#nextjs-app-router]

Wrap your {children}{:ts} with the NuqsAdapter{:ts} component in your root layout file:

// [!code word:NuqsAdapter]
import { NuqsAdapter } from 'nuqs/adapters/next/app'
import { type ReactNode } from 'react'

export default function RootLayout({
  children
}: {
  children: ReactNode
}) {
  return (
    <html>
      <body>
        <NuqsAdapter>{children}</NuqsAdapter>
      </body>
    </html>
  )
}

Pages router [#nextjs-pages-router]

Wrap the <Component>{:ts} page outlet with the NuqsAdapter{:ts} component in your _app.tsx file:

// [!code word:NuqsAdapter]
import type { AppProps } from 'next/app'
import { NuqsAdapter } from 'nuqs/adapters/next/pages'

export default function MyApp({ Component, pageProps }: AppProps) {
  return (
    <NuqsAdapter>
      <Component {...pageProps} />
    </NuqsAdapter>
  )
}

Unified (router-agnostic) [#nextjs-unified]

If your Next.js app uses both the app and pages routers and the adapter needs to be mounted in either, you can import the unified adapter, at the cost of a slightly larger bundle size (~100B).

import { NuqsAdapter } from 'nuqs/adapters/next'
<br/>

The main reason for adapters is to open up nuqs to other React frameworks:

<ReactSPA className='inline mr-1.5 -mt-1' role="presentation"/> React SPA [#react-spa]

Example, with Vite:

// [!code word:NuqsAdapter]
import { NuqsAdapter } from 'nuqs/adapters/react'

createRoot(document.getElementById('root')!).render(
  <NuqsAdapter>
    <App />
  </NuqsAdapter>
)
<Callout title="Note"> Because there is no known server in this configuration, the [`shallow: false{:ts}`](/docs/options#shallow) option will have no effect.

See below for some options: </Callout>

Full page navigation on <br className='hidden [#nd-toc_&]:block'/>shallow: false{:ts} [#full-page-navigation-on-shallow-false]

<FeatureSupportMatrix introducedInVersion='2.4.0' support={{ supported: true, frameworks: ['React SPA'] }}/>

You can specify a flag to perform a full-page navigation when updating query state configured with shallow: false{:ts}, to notify the web server that the URL state has changed, if it needs it for server-side rendering other parts of the application than the static React bundle:

// [!code word:fullPageNavigationOnShallowFalseUpdates]
createRoot(document.getElementById('root')!).render(
  <NuqsAdapter fullPageNavigationOnShallowFalseUpdates>
    <App />
  </NuqsAdapter>
)

This may be useful for servers not written in JavaScript, like Django (Python), Rails (Ruby), Laravel (PHP), Phoenix (Elixir) etc...

<Remix className='inline mr-1.5 -mt-1' role="presentation"/> Remix [#remix]

// [!code word:NuqsAdapter]
import { NuqsAdapter } from 'nuqs/adapters/remix'

// ...

export default function App() {
  return (
    <NuqsAdapter>
      <Outlet />
    </NuqsAdapter>
  )
}

<ReactRouter className='inline mr-1.5 -mt-1' role="presentation"/> React Router v6 [#react-router-v6]

// [!code word:NuqsAdapter]
import { NuqsAdapter } from 'nuqs/adapters/react-router/v6'
import { createBrowserRouter, RouterProvider } from 'react-router-dom'
import App from './App'

const router = createBrowserRouter([
  {
    path: '/',
    element: <App />
  }
])

export function ReactRouter() {
  return (
    <NuqsAdapter>
      <RouterProvider router={router} />
    </NuqsAdapter>
  )
}
<Callout>

Only BrowserRouter is supported. There may be support for HashRouter in the future (see issue #810), but support for MemoryRouter is not planned.

</Callout>

<ReactRouterV7 className='inline mr-1.5 -mt-1' role="presentation"/> React Router v7 [#react-router-v7]

// [!code word:NuqsAdapter]
import { NuqsAdapter } from 'nuqs/adapters/react-router/v7'
import { Outlet } from 'react-router'

// ...

export default function App() {
  return (
    <NuqsAdapter>
      <Outlet />
    </NuqsAdapter>
  )
}
<Callout type="warn" title="Deprecation notice"> The generic import `nuqs/adapters/react-router` (pointing to v6) is deprecated and will be removed in nuqs@3.0.0.

Please pin your imports to the specific version, eg: nuqs/adapters/react-router/v6 or nuqs/adapters/react-router/v7.

The main difference is where the React Router hooks are imported from: react-router-dom for v6, and react-router for v7. </Callout>

<TanStackRouter className='inline mr-1.5 -mt-1 not-prose' role="presentation"/> TanStack Router [#tanstack-router]

// [!code word:NuqsAdapter]
import { NuqsAdapter } from 'nuqs/adapters/tanstack-router'
import { Outlet, createRootRoute } from '@tanstack/react-router'

export const Route = createRootRoute({
  component: () => (
    <>
      <NuqsAdapter>
        <Outlet />
      </NuqsAdapter>
    </>
  ),
})
<Callout>

TanStack Router support is experimental and does not yet cover TanStack Start.

</Callout>

Type-safe routing via validateSearch

TanStack Router comes with built-in type-safe search params support, and its APIs should likely be used in your application code for best DX.

Nevertheless, sometimes you may need to import a component that uses nuqs (from NPM or a shared library), and benefit from TanStack Router's type-safe routing.

You may do so via the Standard Schema support:

import { createFileRoute, Link } from '@tanstack/react-router'
import {
  createStandardSchemaV1,
  parseAsIndex,
  parseAsString,
  useQueryStates
} from 'nuqs'

const searchParams = {
  searchQuery: parseAsString.withDefault(''),
  pageIndex: parseAsIndex.withDefault(0),
}

export const Route = createFileRoute('/search')({
  component: RouteComponent,
  // [!code highlight:3]
  validateSearch: createStandardSchemaV1(searchParams, {
    partialOutput: true
  })
})

function RouteComponent() {
  // Consume nuqs state as usual:
  const [{ searchQuery, pageIndex }] = useQueryStates(searchParams)
  // But now TanStack Router knows about it too:
  return (
    <Link
      to="/search"
      search={{
        searchQuery: 'foo',
        // note: we're not specifying pageIndex
      }}
    />
  )
}

Note that the partialOutput{:ts} flag allows specifying only a subset of the search params for a given route. It also does not reflect those search in the URL automatically, following nuqs' behaviour more closely.

<Callout title="Caveats" type="warn">

Due to differences in how TanStack Router and nuqs handle serialisation and deserialisation (global in TanStack Router and per-key in nuqs), only trivial state types are supported for type-safe linking. Those include all string-based parsers (string, enum, literals), number-based (integer, float, number literal), boolean, and JSON.

The urlKeys feature to provide shorthand key names is also not supported for similar reasons.

</Callout>

<Vitest className='inline mr-1.5 -mt-1' role="presentation"/> Testing

<Callout> Documentation for the `NuqsTestingAdapter{:ts}` is on the [testing page](/docs/testing). </Callout>
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•

← Root | ↑ Up