Skip to main content

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

defaultInit
URLSearchParamsInit
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

[0]
URLSearchParams
The current search params as a URLSearchParams object. This is a stable reference that won’t change between renders.
[1]
SetURLSearchParams
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.
navigateOpts
NavigateOptions
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.
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

Form filters

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;
}

Build docs developers (and LLMs) love