A URL builder and parser pack for handling URL states the easy way.
Using npm:
npm install love-urlUsing yarn:
yarn add love-urlUsing pnpm:
pnpm add love-urltype MyParams = {
showDetails: boolean;
page: number;
tags: string[];
status: "draft" | "published" | "archived";
};
// Encode to URL
// existing params PRESERVED
// currentPath PRESERVED
const url = loveUrl<MyParams>({
showDetails: true,
page: 2,
tags: ["food", "travel"],
status: "published",
// This param will be removed
car: undefined,
});
// Pre-existing params ?name=bob&car=fiat%20multipla&page=1
/*
url = "/current-path?name=bob&showDetails=true&page=2&tags=_._food_._travel&status=published"
*/
// Encode to URL (existing params REMOVED)
const url = loveUrl<MyParams>(
{
showDetails: true,
page: 2,
tags: ["food", "travel"],
status: "published",
},
{
currentParams: null,
url: "/route-somewhere-else",
}
);
// Pre-existing params ?name=bob&page=1
/*
url = "/route-somewhere-else?showDetails=true&page=2&tags=_._food_._travel&status=published"
*/
// Decode from URL
const parsed = parseLoveUrl<MyParams>(
"?showDetails=true&page=2&tags=_._food_._travel&status=published"
// or window.location.search
);
/*
parsed = {
showDetails: true,
page: 2,
tags: ["food", "travel"],
status: "published"
}
*/- Arrays are encoded using a custom separator:
_._
This ensures:- Consistent decoding even with a single item (
tags=_._designβ["design"]) - Reliable parsing when array items contain commas
- Consistent decoding even with a single item (
- Booleans and numbers are parsed and typed automatically
- Invalid values (e.g.,
status=broken) will be parsed asstringsunless custom validation is added
loveUrl aims to simplify the common headaches when building and parsing URLs with parameters in modern JavaScript projects.
Imagine your user is at /currentPath/example and the current URL params are:
fileType=photo&selectedPeriod=weekly
Instead of manually constructing links, you can just use:
const ExampleComponent = () => (
<div>
{/* Renders: /currentPath/example?fileType=photo&selectedOption=option1&selectedPeriod=weekly */}
<a href={loveUrl({ selectedOption: "option1" })}>Option 1</a>
{/* Renders: /currentPath/example?fileType=photo&selectedOption=option2&selectedPeriod=weekly */}
<a href={loveUrl({ selectedOption: "option2" })}>Option 2</a>
{/* Renders: /currentPath/example?fileType=photo&selectedPeriod=weekly */}
<a href={loveUrl({ selectedOption: undefined })}>Clear</a>
</div>
);Building parameterized API URLs manually can get messy:
type DynamicDataOptions = {
startDate?: string;
endDate?: string;
format?: "photos" | "videos";
limit: number;
};
const fetchDynamicData = (params: DynamicDataOptions) => {
let dataUrl = "https://api.my-project/files/archive";
// Prevent undefined values from appearing in the query string
for (const key in params) {
if (params[key] === undefined) {
delete params[key];
}
}
const queryString = new URLSearchParams(params).toString();
if (queryString) dataUrl += `?${queryString}`;
const req = await fetch(dataUrl);
return await req.json();
};Or even worse:
const fetchDynamicData = ({
startDate,
endDate,
format,
limit,
}: DynamicDataOptions) => {
const req = await fetch(
`https://api.my-project/files/archive?startDate=${startDate}&endDate=${endDate}&format=${format}&limit=${limit}`
);
return await req.json();
};Imagine doing this with 12+ parameters π
const fetchDynamicData = (params: DynamicDataOptions) => {
const req = await fetch(
loveUrl(params, { url: "https://api.my-project/files/archive" })
);
return await req.json();
};Clean. Type-safe. No string interpolation errors.
Handling conversions manually can quickly get out of hand:
const ComponentThatUsesParams = () => {
const params = new URLSearchParams(window.location.search);
const myBoolean = params.get("myBoolean") === "true"; // string 'false' is truthy π¬
const limit = parseInt(params.get("limit"));
const percentage = parseFloat(params.get("percentage"));
let favoriteFoods = params.get("favoriteFoods");
if (favoriteFoods?.includes(",")) {
favoriteFoods = favoriteFoods.split(",");
}
return (
<div>
<h1>My Params as an object:</h1>
<code>
{JSON.stringify({
myBoolean,
limit,
percentage,
})}
</code>
</div>
);
};const ComponentThatUsesParams = () => {
const { myBoolean, limit, percentage, favoriteFoods } = parseLoveUrl<{
myBoolean: boolean;
limit: number;
percentage: number;
favoriteFoods: string[];
}>(window.location.search);
return (
<div>
<h1>My Params as an object:</h1>
<code>
{JSON.stringify({
myBoolean,
limit,
percentage,
})}
</code>
</div>
);
};Type-safe, clean, and handles all conversions for you.
- Automatically ignores
undefinedvalues - Handles complex param types like arrays, numbers, and booleans
- Uses a custom array separator (
_._) for full consistency - Prevents messy string interpolation
- Decodes and encodes with full TypeScript support
- Deals with duplicate params gracefully
- Keeps your URLs and logic clean and reliable