MDN URLSearchParams - discussion (2022-12-24)
URLSearchParams is one of those APIs that looks trivial until you try to use it as part of your routing story. We have a bunch of screens where the query is effectively route state (filters, sort, tab) and I keep seeing teams invent their own parsing conventions.
Do you treat search params as a first-class route contract, or as a convenience for shareable links? How do you encode complex state without turning URLs into unreadable blobs? What is your strategy for keeping query parsing consistent across file routes and component routes?
Comments (10)
Back to latestIf filters matter, the URL is the contract. Otherwise you cannot reproduce issues.
We standardized on a tiny codec layer per route so parsing is not scattered.
Related: Routing and Navigation.
Simple pattern: keep keys stable and store derived evidence so you can render it in the shell.
ts
export function readFilters(search: string) {
const p = new URLSearchParams(search);
return { tab: p.get('tab') ?? 'all', sort: p.get('sort') ?? 'recent' };
}Counterpoint: I think too many apps over-index on putting state in the URL.
It is useful for shareability, but it can become a leaky persistence layer.
I agree for deep internal UI state. For filter/search/sort, the URL has been a win for us.
The part that failed was inconsistency: every route used different key names and different parsing rules.
That distinction is fair: URL for the user-visible contract, not for every internal toggle.
If you want it to stay sane, do not encode arbitrary JSON in the query.
Make the route own a small vocabulary of keys and value shapes.
We also do a small normalization step so support can read links.
For example, we map synonyms (new -> recent) instead of breaking old links.
A misunderstanding I had: I assumed URLSearchParams preserves type.
Once you accept everything is string, you stop trying to be clever and just define a route codec.
We render the parsed filter state as evidence in internal builds:
tsx
return <section data-tab={tab} data-sort={sort} />;
It sounds silly, but it made debugging link-driven state a lot faster.
Once you treat query params as route posture, the rest is just naming and normalization.
I like MDN here because it reminds you what the platform guarantees and what it does not.
The rest is your routing story.