Appearance
RelativeURL
When to use
Use RelativeURL when you need URL parsing and manipulation but want relative paths instead of absolute URLs. Common in single-page applications where links should produce /path?query#hash rather than http://localhost:3000/path?query#hash. Also useful for server-side route generation where the origin is irrelevant.
The pattern
A RelativeURL class extends the built-in URL. The constructor provides a dummy base so that relative paths can be parsed without requiring an origin. Getters for href, origin, protocol, username, password, host, hostname, and port are overridden to return empty strings or the relative form.
Basic usage
Construct a RelativeURL with a path string. It parses like a standard URL but strips the origin from output — href returns only the path, query, and hash:
javascript
const url = new RelativeURL("/users?page=2#top");
url.href; // "/users?page=2#top"
url.pathname; // "/users"
url.search; // "?page=2"
url.hash; // "#top"
url.origin; // ""
url.hostname; // ""Parsing a relative path
Because URL requires a base, RelativeURL supplies a dummy origin so relative paths parse correctly:
javascript
const url = new RelativeURL("/api/items/42");
url.pathname; // "/api/items/42"
url.href; // "/api/items/42"Modifying URL components
All inherited URL setters (like searchParams) still work. Only the output is relative:
javascript
const url = new RelativeURL("/search");
url.searchParams.set("q", "hello world");
url.searchParams.set("page", "1");
url.href;
// "/search?q=hello+world&page=1"Updating href
Assigning to href re-parses through RelativeURL so the result stays relative:
javascript
const url = new RelativeURL("/old");
url.href = "/new?updated=true";
url.pathname; // "/new"
url.search; // "?updated=true"
url.href; // "/new?updated=true"SPA navigation
Build relative links for history.pushState() without an origin prefix:
javascript
function navigate(path) {
const url = new RelativeURL(path);
history.pushState(null, "", url.href);
}
navigate("/dashboard?tab=settings#profile");
// pushes "/dashboard?tab=settings#profile"Implementing RelativeURL
The class extends URL with a dummy base so that relative paths parse without an origin. Getters for href, origin, protocol, and other origin-related properties are overridden to return empty strings or the relative form.
javascript
export class RelativeURL extends URL {
constructor(input, base = "http://unspecified") {
super(input, base);
}
get href() {
return this.pathname + this.search + this.hash;
}
set href(value) {
const url = new RelativeURL(value);
this.pathname = url.pathname;
this.search = url.search;
this.hash = url.hash;
}
get origin() { return ""; }
get protocol() { return ""; }
get username() { return ""; }
get password() { return ""; }
get host() { return ""; }
get hostname() { return ""; }
get port() { return ""; }
}Trade-offs
- Pros: Full
URLAPI (searchParams, pathname manipulation) without origin leaking into output. Drop-in replacement anywhere a relative href is needed.instanceof URLreturns true. - Cons: The dummy base
"http://unspecified"meanstoString()(inherited fromURL) still returns an absolute URL unless you use.href. Callers must use.hreffor relative output. - Versus string concatenation:
RelativeURLgives you proper encoding, searchParams, and parsing. Concatenating path segments manually is error-prone with special characters and query strings. - Versus URL with real base: Use
new URL(path, base)when you actually need absolute URLs. UseRelativeURLwhen the origin is irrelevant or should be stripped.