Managing Filters In the URL in React: A Practical Guide - Part 2
Written by Lucie Zdeňková on 2025-12-04
reactjavascriptIn our last post Managing Filters In the URL in React: A Practical Guide - Part 1, we shared how to synchronize filter values with the URL on the simpliest example with full-text filter. In today's post, we will explore, how to alter those function to handle multi-select or from-to filters values in the URL. Let's get into it.
Multi-select
Multi-select is useful in various cases, when you aim to allow the choice of several
options. Like in full-text filter mentioned in previous blog, we are using similar
logic in following functions - read from URL, write to URL and merge those to update
the URL. Our multi-select value is dictionary such as {1: true, 2:false,
3:true}, where the key is id of the option and the value is boolean
representing whether option is checked.
1. Extract function
In the case of a multi-select filter, the URL can contain multiple values under the
same parameter name, for example:
www.example.com/documents?status=2&status=3&status=4&status=5&status=6.
The purpose of the extraction function is to read all of these values and translate them into a dictionary format. The algorithm steps are:
- collecting all occurrences of the parameter using
params.getAll(key), - turning them into a
Setfor lookup, - iterating through all possible filter
ids, - and producing an object where each
idmaps to a boolean (true is selected, false is not selected).
If no values are present in the URL, the function defaults to selecting all options.
function extract_field_from_params_multiselect(params, key, def_dict = "") {
const selected = new Set(params.getAll(key));
const allIds = Object.keys(def_dict);
const val = Object.fromEntries(allIds.map((id) => [id, selected.size === 0 || selected.has(id)]));
return val;
}
2. Update filter value in the URL
Update function first deletes all occurrences of the mentioned param
status. Then it rewrites new value of the multi-select filter to the URL
by looping through the dictionary of selected values and appending each active option
back into the query string.
function set_field_to_params_multiselect(params, key, val) {
const newParams = new URLSearchParams(params);
newParams.delete(key);
Object.entries(val).forEach(([id, checked]) => {
if (checked) {
newParams.append("status", id);
}
});
return newParams;
}
3. Final update function
Final function that merges the previous ones follows the same logic as in the
full-text filter case in previous blog. The function returns a
[val, setter] pair that behaves similarly to React’s
useState. Thanks to this, handling filters stored in the URL feels just
like using React useState hook, but with the benefit that the URL remains
the single source of truth.
export function use_params_field_multiselect(params, setParams, key, def_dict = "") {
const val = extract_field_from_params_multiselect(params, key, def_dict);
const setter = (val) => {
setParams(set_field_to_params_multiselect(params, key, val));
}
return [val, setter];
}
From-to range filter
From-to range filters are very useful when it comes to numbers. We store the value
in an array ["", ""].
1. Extract function
This helper retrieves a range filter (typically something like a date range or
numeric interval) from the URL. Instead of storing both values under a single query
parameter, the range is split into two keys following a consistent naming pattern:
key_from and key_to.
The function builds the expected parameter names (e.g., price_from, price_to), it
reads all occurrences of each key from the URL. If no values are found, it falls back
to a default values ["", ""]. It returns a two-element array
[fromValue, toValue] that you can directly use in your component
state.
function extract_range_field_from_params(params, key, defval = ["", ""]) {
const keyFrom = key + "_from";
const keyTo = key + "_to";
const valsFrom = params.getAll(keyFrom);
const valsTo = params.getAll(keyTo);
const valFrom = valsFrom.length === 0 ? defval[0] : valsFrom[0];
const valTo = valsTo.length === 0 ? defval[1] : valsTo[0];
return [valFrom, valTo];
}
2. Update filter value in the URL
This function updates the URL so that it reflects the current state of a range filter.
It generates the appropriate parameter names: key_from and key_to. A
fresh copy of the current URL parameters is created, followed by deletion of any
existingsting values for the range filter. The new range values are appended in the
correct order: first the from value, then the to value. Finally, it returns an updated
URLSearchParams instance ready to be pushed into the URL.
function set_range_field_to_params(params, key, val) {
const keyFrom = key + "_from";
const keyTo = key + "_to";
const newParams = new URLSearchParams(params);
newParams.delete(keyFrom);
newParams.delete(keyTo);
newParams.append(keyFrom, val[0]);
newParams.append(keyTo, val[1]);
return newParams;
}
3. Final update function
Final function to use has again same logic as previously, meanwhile being easy to
use thanks to the [val, setter] pair.
export function use_params_range_field(params, setParams, key, defval = ["", ""]) {
const val = extract_range_field_from_params(params, key, defval);
const setter = (val) => {
setParams(set_range_field_to_params(params, key, val));
}
return [val, setter];
}
Implementation in components
Simply call the function in your component and don't forget to use the values
multiSelectStatus amountFilter to white a filter function for your actual
data.
const [multiSelectStatus, setMultiSelectStatus] = use_params_field_multiselect(searchParams, setSearchParams, "status", {1: true, 2: true, 3: true});
const [amountFilter, setAmountFilter] = use_params_range_field(searchParams, setSearchParams, "amount");
In this blog post, we shared how to handle update of filter in URL for two very common filter use cases - multi-select and from-to range filter. We hope this blog was useful, happy coding and see ya next time!