npm.io
0.2.0-next.1 • Published 2d ago

@solid-primitives/url

Licence
MIT
Version
0.2.0-next.1
Deps
5
Size
42 kB
Vulns
0
Weekly
0
Stars
1.5K

Solid Primitives url

@solid-primitives/url

lerna version stage tested with vitest

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.

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 — uses history.pushState
  • replace — uses history.replaceState
  • navigate — overwrites location.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:

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.

Changelog

Expand Changelog

0.1.0

Rewritten for Solid 2.0. Adapted from the original design proposed in PR #77.

Keywords