@solid-primitives/url
Reactive primitives for the Browser's Location, URL, and URLSearchParams interfaces.
Already using Solid Router? It already covers a lot of the same ground — reactive location, search params, and navigation — and is the better choice if you need routing anyway. These primitives are for when you want that reactivity without pulling in a router, e.g. in a non-routed app or a library.
createLocationState— Reactivewindow.locationstate, withpush/replace/navigatesetters.useSharedLocationState— Shared-root version ofcreateLocationState.updateLocation— Non-reactive helper to push, replace, or navigate to a new href.createURL/ReactiveURL— A reactiveURL-like object.createURLRecord— AURLinstance as a reactive store.createSearchParams/ReactiveSearchParams— A reactiveURLSearchParams-like object.createLocationSearchParams— Reactive record ofwindow.location.search.
Installation
npm install @solid-primitives/url
# or
pnpm add @solid-primitives/url
# or
yarn add @solid-primitives/url
createLocationState
Creates a reactive window.location state. The state updates whenever the location changes —
via back/forward navigation, a #hash change, or history.pushState/replaceState — and can be
modified using the provided setter methods.
import { createLocationState } from "@solid-primitives/url";
const [state, { push }] = createLocationState();
state.href; // => "http://example.com/"
push({ hash: "heading1" });
state.href; // => "http://example.com/#heading1"
Setter methods
createLocationState provides three setter methods for updating the window.location state.
All have the same interface, but cause different side effects:
push— useshistory.pushStatereplace— useshistory.replaceStatenavigate— overwriteslocation.href, forcing a full navigation
Each setter accepts either a partial record (or an updater function returning one), or a single
(key, value) pair:
push({ pathname: "/other", hash: "top" });
push(prev => ({ search: prev.search + "&page=2" }));
push("hash", "top");
Server fallback
location isn't available on the server, so a fallback has to be provided — either per-call, or
globally with setLocationFallback (call it before the primitives that rely on it):
// fallback can be a href string, a URL instance, or a LocationState object
const [state] = createLocationState("http://example.com");
// or globally, once, before rendering:
setLocationFallback("http://example.com");
const [state] = createLocationState();
useSharedLocationState
Reuses a singleton root
createLocationState, or creates one if one isn't active yet. Use it instead of
createLocationState to avoid recreating signals, computations, and event listeners for every
consumer. Its interface is the same, minus the fallback argument — use setLocationFallback
instead.
const [state, { push }] = useSharedLocationState();
updateLocation
A non-reactive utility to push, replace, or navigate to a new href.
updateLocation("http://example.com?foo=bar", "push");
createURL
Creates an instance of ReactiveURL.
import { createURL } from "@solid-primitives/url";
const url = createURL("http://example.com");
url.host; // => "example.com"
url.search = "?foo=bar";
createEffect(() => console.log(url.href));
ReactiveURL
An object providing reactive setters and getters for managing a URL — same interface as the
native URL class, but every getter is granularly reactive, causing updates only when its value
has actually changed.
ReactiveURL does not extend URL, so x instanceof URL won't hold. As a reactive
structure, it should be instantiated under a reactive root (e.g. inside createRoot or a
component).
const url = new ReactiveURL("http://example.com");
url.host; // => "example.com"
url.search = "?foo=bar";
url.hash = "heading1";
createEffect(() => console.log(url.href));
searchParams
Same as the native URL class, ReactiveURL provides a searchParams getter, returning an
instance of ReactiveSearchParams kept in sync with url.search in
both directions. The reference is stable, so it can be destructured freely.
const url = new ReactiveURL("http://example.com");
const { searchParams } = url;
createEffect(() => console.log(searchParams.get("foo")));
url.search = "?foo=bar"; // reruns the effect above
searchParams.set("foo", "baz"); // updates url.search to "?foo=baz"
createURLRecord
Provides a URL instance as a reactive store.
import { createURLRecord } from "@solid-primitives/url";
const [url, setURL] = createURLRecord("http://example.com");
url.host; // => "example.com"
setURL({ hash: "heading1" });
url.hash; // => "#heading1"
createSearchParams
Creates an instance of ReactiveSearchParams.
const params = createSearchParams("foo=1&foo=2&bar=baz");
ReactiveSearchParams
A reactive version of the URLSearchParams class. Every read method is granular — it causes an
update only when the value it read has actually changed.
ReactiveSearchParams extends URLSearchParams, so x instanceof URLSearchParams holds. As a
reactive structure, it should be instantiated under a reactive root.
const params = new ReactiveSearchParams("foo=1&foo=2&bar=baz");
createEffect(() => console.log(params.getAll("foo")));
params.append("foo", "3");
createLocationSearchParams
Provides a reactive record reflecting window.location.search, updating whenever the browser's
search params change, along with setter methods to update them.
import { createLocationSearchParams } from "@solid-primitives/url";
const [params, { push }] = createLocationSearchParams();
params.foo; // T: string | string[] | undefined
push({ ...params, page: "2" });
Passing (name, value) updates a single param, keeping the rest of the query string intact:
push("page", "3");
Options:
useSharedState— use the shared-root version of the reactive location state (seeuseSharedLocationState).
useSharedLocationSearchParams
Reuses a shared-root createLocationSearchParams, or creates one if one isn't active.
const [params, { push }] = useSharedLocationSearchParams();
getSearchParamsRecord
A non-reactive helper turning a URLSearchParams instance (or a search string) into a plain
record — a single value for names that appear once, an array of values for names that repeat.
import { getSearchParamsRecord } from "@solid-primitives/url";
const record = getSearchParamsRecord("?foo=bar");
record; // => { foo: "bar" }
Demo
You can play with a live demo here.