How to read and update URL query params without regex
Sponsor this newsletter · reach 9,500+ active developers
A filter sidebar, a sort dropdown, a pagination control. All of them need to read and write query parameters like ?category=shoes&sort=price. The instinct is often to split the string on & and = by hand, which breaks on encoding edge cases. URLSearchParams is a built-in class that does all of this correctly, with a clean API.
Reading params from the current page
// url: yoursite.com/products?category=shoes&sort=price
const params = new URLSearchParams(location.search);
params.get('category'); // 'shoes'
params.get('sort'); // 'price'
params.get('missing'); // null — no error, just null
params.has('category'); // true
No splitting strings, no decoding percent-encoded characters manually. URLSearchParams handles encoding and decoding automatically, including spaces, special characters, and repeated keys.
Updating params and syncing the URL
Update a param and push the new URL without a full page reload, using history.pushState:
function setFilter(key, value) {
const params = new URLSearchParams(location.search);
params.set(key, value);
const newUrl = `${location.pathname}?${params.toString()}`;
history.pushState({}, '', newUrl);
}
// usage
setFilter('sort', 'rating');
// url becomes: ?category=shoes&sort=rating
setFilter('page', '2');
// url becomes: ?category=shoes&sort=rating&page=2
The user can now refresh the page, share the link, or bookmark it, and the filters stay exactly where they left them. This is the foundation behind every “shareable filtered URL” feature on e-commerce and search sites.
Removing a param entirely
function clearFilter(key) {
const params = new URLSearchParams(location.search);
params.delete(key);
const query = params.toString();
const newUrl = query
? `${location.pathname}?${query}`
: location.pathname;
history.pushState({}, '', newUrl);
}
The ternary handles the edge case where removing the last param should leave a clean URL with no trailing question mark.
It also works for building URLs to send elsewhere. Use URLSearchParams to construct query strings for fetch requests too, instead of manually concatenating strings: fetch('/api/search?' + new URLSearchParams({ q: userInput, page: 1 })). Special characters in userInput are escaped automatically.
Why it matters
- Correct encoding by default. Spaces, ampersands, and special characters in values are handled automatically. Manual string splitting gets this wrong constantly.
- Shareable, bookmarkable state. Filters, sort order, and pagination synced to the URL survive refreshes and can be shared as a link.
- All browsers. Baseline 2017. No library needed for something this fundamental to building filterable interfaces.
Any filter, sort, or search feature that does not survive a page refresh is a candidate for syncing its state to the URL with URLSearchParams. It is a small change that makes an interface feel significantly more polished.
Happy coding!
Marko