Suspense for search params

Wrap useSearchParams in Suspense, and dynamic usePathname.

From next-best-practices, suspense-boundaries.md.

What arrives in the HTML

Press Load page, then change JS timing or tick JS fails.

No boundaryBad
In <Suspense>Good
// app/search/page.tsx (Server Component)
import { Suspense } from 'react'
import SearchBar from './search-bar'

export default function Page() {
  return (
    <>
      <Header />
      <Suspense fallback={<div>Loading...</div>}>
        <SearchBar />   {/* 'use client' + useSearchParams() */}
      </Suspense>
      <Article />
    </>
  )
}

Which hooks need a boundary

Click a cell to see the rule.

Suspense boundaryRequired

Suspense requirement by hook and route type
HookStaticDynamic [slug]Dynamic + generateStaticParams

View source

Switch mode and phase, then edit ?q= in the toolbar.

view-source:/search?q=linenServer

      

Why it matters, pros and cons

Why it matters

The query is unknown at prerender, so its reader bails out to a boundary.

Pros

  • Header and article stay in prerendered HTML.
  • The page still reads if JS fails.
  • The fallback reserves the slot, no jump.

Cons

  • The fallback shows until hydration; size it to match.
  • Need it on the server? Read the searchParams prop.
  • useParams() and useRouter() never need one.