usePathname & useSearchParams
Beyond triggering navigation, Client Components often need to read information about the current URL — which path is active, or what query parameters are set. Next.js provides two hooks for exactly this: usePathname and useSearchParams.
usePathname
usePathname returns the current URL's pathname as a plain string, without the query string. It's most commonly used to highlight an active navigation item.
'use client'
import Link from 'next/link'
import { usePathname } from 'next/navigation'
const links = [
{ href: '/', label: 'Home' },
{ href: '/blog', label: 'Blog' },
{ href: '/contact', label: 'Contact' },
]
export function NavBar() {
const pathname = usePathname()
return (
<nav>
{links.map((link) => (
<Link
key={link.href}
href={link.href}
className={pathname === link.href ? 'active' : undefined}
>
{link.label}
</Link>
))}
</nav>
)
}useSearchParams
useSearchParams returns a read-only version of the standard URLSearchParams interface, letting you read individual query string values reactively — the component re-renders whenever the search params change.
'use client'
import { useSearchParams } from 'next/navigation'
export function SortIndicator() {
const searchParams = useSearchParams()
const sort = searchParams.get('sort') ?? 'newest'
return <p>Sorting by: {sort}</p>
}Worked Example: A Filter UI
A common pattern combines both hooks with useRouter to build filter controls that update the URL, which in turn drives what data gets shown — keeping the current filter shareable and bookmarkable via the URL itself.
'use client'
import { useRouter, usePathname, useSearchParams } from 'next/navigation'
const categories = ['all', 'tutorials', 'news', 'reviews']
export function CategoryFilter() {
const router = useRouter()
const pathname = usePathname()
const searchParams = useSearchParams()
const activeCategory = searchParams.get('category') ?? 'all'
function handleSelect(category: string) {
const params = new URLSearchParams(searchParams.toString())
params.set('category', category)
router.push(`${pathname}?${params.toString()}`)
}
return (
<div>
{categories.map((category) => (
<button
key={category}
onClick={() => handleSelect(category)}
disabled={category === activeCategory}
>
{category}
</button>
))}
</div>
)
}Both Are Client-Only Hooks
Hook | Returns | Component Type |
|---|---|---|
usePathname() | The current path as a string, e.g. /blog/first-post | Client Component |
useSearchParams() | A read-only URLSearchParams-like object | Client Component |
// Server Component page — no hook needed
export default function SearchResultsPage({
searchParams,
}: {
searchParams: { q?: string }
}) {
return <h1>Results for: {searchParams.q}</h1>
}usePathname never includes the query string — only the path segments.
useSearchParams().get(key) returns null, not undefined, when a key is absent.
Both hooks come from next/navigation, alongside useRouter.
Wrap components that call useSearchParams in a Suspense boundary if you need finer control over loading states during navigation.
Together, usePathname and useSearchParams give Client Components a live, reactive window into the current URL — the natural counterpart to the params and searchParams props that Server Component pages receive directly.