useSearchParams
Returns a tuple of the current URL’s URLSearchParams and a function to update them. Setting the search params causes a navigation.
Signature
function useSearchParams(
defaultInit?: URLSearchParamsInit
): [URLSearchParams, SetURLSearchParams]
type SetURLSearchParams = (
nextInit?:
| URLSearchParamsInit
| ((prev: URLSearchParams) => URLSearchParamsInit),
navigateOpts?: NavigateOptions
) => void
Parameters
Optional default search params. This will not change the URL on the first render.Can be:
- A search param string (e.g.,
"?tab=1")
- A shorthand object (e.g.,
{ tab: "1" })
- An object with array values (e.g.,
{ brand: ["nike", "reebok"] })
- An array of tuples (e.g.,
[["tab", "1"]])
- A
URLSearchParams object
Returns
The current search params as a URLSearchParams object. This is a stable reference that won’t change between renders.
A function to update the search params and navigate to the new URL.nextInit
URLSearchParamsInit | function
The new search params or a function that receives the current params and returns new params.
Optional navigation options like replace, state, preventScrollReset, etc.
Usage
Basic usage
import { useSearchParams } from "react-router";
function SearchFilter() {
const [searchParams, setSearchParams] = useSearchParams();
return (
<div>
<p>Current query: {searchParams.get("q")}</p>
<button
onClick={() => setSearchParams({ q: "react" })}
>
Search for React
</button>
</div>
);
}
Set search params
Multiple ways to set search params:
const [searchParams, setSearchParams] = useSearchParams();
// String
setSearchParams("?tab=1");
// Object
setSearchParams({ tab: "1" });
// Multiple values for same key
setSearchParams({ brand: ["nike", "reebok"] });
// Array of tuples
setSearchParams([["tab", "1"]]);
// URLSearchParams object
setSearchParams(new URLSearchParams("?tab=1"));
Function callback
Update search params based on current values:
setSearchParams((prev) => {
prev.set("tab", "2");
return prev;
});
The function callback version does not support React’s setState queueing logic. Multiple calls in the same tick will not build on the prior value.
Navigation options
Pass navigation options as the second argument:
// Replace history entry instead of pushing
setSearchParams(
{ tab: "2" },
{ replace: true }
);
// Prevent scroll reset
setSearchParams(
{ tab: "2" },
{ preventScrollReset: true }
);
Read search params
const [searchParams] = useSearchParams();
// Get single value
const query = searchParams.get("q");
// Get all values for a key
const brands = searchParams.getAll("brand");
// Check if key exists
const hasFilter = searchParams.has("filter");
// Iterate over all params
for (const [key, value] of searchParams) {
console.log(key, value);
}
Default search params
Provide default values that won’t change the URL initially:
const [searchParams, setSearchParams] = useSearchParams({
tab: "home",
});
// On first render: searchParams.get("tab") === "home"
// URL remains unchanged unless user navigates to the page
function ProductFilters() {
const [searchParams, setSearchParams] = useSearchParams();
return (
<form
onChange={(e) => {
const formData = new FormData(e.currentTarget);
setSearchParams(formData);
}}
>
<input
type="search"
name="q"
defaultValue={searchParams.get("q") || ""}
/>
<select
name="category"
defaultValue={searchParams.get("category") || ""}
>
<option value="">All Categories</option>
<option value="shoes">Shoes</option>
<option value="clothing">Clothing</option>
</select>
</form>
);
}
Tab navigation
function Tabs() {
const [searchParams, setSearchParams] = useSearchParams();
const activeTab = searchParams.get("tab") || "profile";
return (
<div>
<nav>
<button
onClick={() => setSearchParams(
{ tab: "profile" },
{ preventScrollReset: true }
)}
>
Profile
</button>
<button
onClick={() => setSearchParams(
{ tab: "settings" },
{ preventScrollReset: true }
)}
>
Settings
</button>
</nav>
{activeTab === "profile" && <Profile />}
{activeTab === "settings" && <Settings />}
</div>
);
}
Preserve other params
function UpdateSort() {
const [searchParams, setSearchParams] = useSearchParams();
const updateSort = (sort: string) => {
setSearchParams((prev) => {
prev.set("sort", sort);
// Other params like "q", "filter" are preserved
return prev;
});
};
return (
<button onClick={() => updateSort("date")}>
Sort by Date
</button>
);
}
Clear search params
// Clear all params
setSearchParams({});
// Or
setSearchParams("");
// Remove specific param
setSearchParams((prev) => {
prev.delete("filter");
return prev;
});
Important Notes
Stable reference
searchParams is a stable reference, safe to use in useEffect dependencies:
useEffect(() => {
const query = searchParams.get("q");
// Perform search
}, [searchParams]);
Mutability warning
The searchParams object is mutable. If you change it without calling setSearchParams, values will change between renders but the URL won’t update:
// ❌ Don't do this
searchParams.set("tab", "2"); // URL won't update!
// ✅ Do this instead
setSearchParams((prev) => {
prev.set("tab", "2");
return prev;
});
Type Safety
Create a type-safe wrapper:
interface SearchParams {
q?: string;
category?: string;
sort?: "date" | "name";
}
function useTypedSearchParams() {
const [searchParams, setSearchParams] = useSearchParams();
const typedParams: SearchParams = {
q: searchParams.get("q") || undefined,
category: searchParams.get("category") || undefined,
sort: (searchParams.get("sort") as "date" | "name") || undefined,
};
return [typedParams, setSearchParams] as const;
}