use-url-filters
v1.0.2
Published
A lightweight React hook for managing URL search parameters in client-side applications
Maintainers
Readme
use-url-filters
A lightweight, framework-agnostic React hook for managing URL search parameters in client-side applications. Perfect for filtering, sorting, and pagination that persists through page refreshes and can be shared via URL.
Features
- 🔍 URL-synchronized filters - Filter state is automatically synchronized with the URL
- 🔗 Shareable URLs - Users can share filtered views via URL
- 🧠 Type Parsing - Automatically parses numbers and booleans from URL parameters
- 📦 Framework Agnostic - Works with any React setup (Next.js, CRA, Vite, etc.)
- 🚫 No Dependencies - Uses only the native browser APIs (Window, URLSearchParams)
- 🧩 Array Support - Multiple formats for handling array values in URLs
- 📜 History Integration - Browser back/forward navigation works with your filters
- 💾 Default Values - Set default filters that apply when none are in the URL
Installation
# npm
npm install use-url-filters
# yarn
yarn add use-url-filters
# pnpm
pnpm add use-url-filtersQuick Start
import useUrlFilters from "use-url-filters";
function ProductList() {
const { filters, setFilter, clearFilters } = useUrlFilters({
category: "all", // Default values
minPrice: 0,
});
// URL will automatically update when filters change
return (
<div>
<select
value={filters.category}
onChange={(e) => setFilter("category", e.target.value)}
>
<option value="all">All Categories</option>
<option value="electronics">Electronics</option>
<option value="clothing">Clothing</option>
</select>
<input
type="range"
value={filters.minPrice || 0}
onChange={(e) => setFilter("minPrice", Number(e.target.value))}
/>
<button onClick={clearFilters}>Reset Filters</button>
</div>
);
}API
useUrlFilters(initialFilters?, options?)
The main hook that manages URL filters.
Parameters
initialFilters(object, optional): Default filters to use if none are in the URLoptions(object, optional): Configuration options:replaceState(boolean): UsereplaceStateinstead ofpushState(default:false)encodeValues(boolean): URI encode parameter values (default:true)arrayFormat(string): Format for arrays:'comma','bracket', or'repeat'(default:'comma')parseNumbers(boolean): Parse numeric strings as numbers (default:true)parseBooleans(boolean): Parse "true"/"false" strings as booleans (default:true)onFilterChange(function): Callback when filters change (params: newFilters)
Returns
Object with the following properties:
filters(object): Current filter valuessetFilter(key, value)(function): Set an individual filtersetFilters(filtersObject)(function): Set multiple filters at onceremoveFilter(key)(function): Remove a filterclearFilters()(function): Clear all filtershasFilters(boolean): Whether any filters are setfilterCount(number): Number of active filters
Examples
E-commerce Product Filtering
function ProductFilters() {
const { filters, setFilter, clearFilters } = useUrlFilters({
query: "",
category: "all",
minPrice: 0,
maxPrice: 1000,
inStock: true,
sort: "popularity",
});
// Component implementation...
}Data Table with Sorting, Filtering and Pagination
function DataTable() {
const { filters, setFilter, setFilters } = useUrlFilters({
page: 1,
limit: 25,
sortBy: "createdAt",
sortDir: "desc",
search: "",
});
// Handle pagination
const goToPage = (page) => {
setFilter("page", page);
};
// Handle column sorting
const handleSort = (column) => {
setFilters({
sortBy: column,
sortDir:
filters.sortBy === column && filters.sortDir === "asc" ? "desc" : "asc",
});
};
// Component implementation...
}Advanced Usage
Multiple Array Formats
// Default comma-separated: ?colors=red,green,blue
const { filters } = useUrlFilters({}, { arrayFormat: "comma" });
// Bracket notation: ?colors[]=red&colors[]=green&colors[]=blue
const { filters } = useUrlFilters({}, { arrayFormat: "bracket" });
// Repeated keys: ?colors=red&colors=green&colors=blue
const { filters } = useUrlFilters({}, { arrayFormat: "repeat" });Custom Type Handling
// Disable automatic type conversion
const { filters } = useUrlFilters(
{},
{
parseNumbers: false,
parseBooleans: false,
}
);
// Manual type conversion
const minPrice = filters.minPrice ? Number(filters.minPrice) : 0;
const isActive = filters.active === "true";Integration with Data Fetching
function ProductList() {
const { filters } = useUrlFilters({ category: "all", page: 1 });
const [products, setProducts] = useState([]);
const [loading, setLoading] = useState(false);
// Fetch products when filters change
useEffect(() => {
const fetchProducts = async () => {
setLoading(true);
try {
const response = await fetch(
`/api/products?${new URLSearchParams(filters)}`
);
const data = await response.json();
setProducts(data);
} catch (error) {
console.error("Error fetching products:", error);
} finally {
setLoading(false);
}
};
fetchProducts();
}, [filters]);
// Component implementation...
}Browser Compatibility
use-url-filters is compatible with all modern browsers that support:
URLSearchParamswindow.history.pushState/replaceStateArray.prototype.forEach
For older browsers, consider using a polyfill for URLSearchParams.
License
MIT
