Skip to content

Routing ​

Routing in PreffX is driven by a root-level url signal. Navigation updates it, and the rendered tree reacts automatically. The library is agnostic to the navigation source: it works with the browser Navigation API when available and falls back to detached, signal-managed navigation in SSR or headless environments.

Reading the URL ​

The url utility is a read-only URL signal:

tsx
import type { PC } from 'preffx';

export const Path: PC = (_props, { url }) => {
    return <p>You are at: {url.value.pathname}</p>;
};

Triggering navigation ​

Use navigate to move to another URL:

tsx
import type { PC } from 'preffx';

export const Go: PC = (_props, { navigate }) => {
    return <button onClick={() => navigate('/about')}>About</button>;
};

Declarative routes with routes ​

The routes utility takes a map of path pattern → component and returns a reactive signal holding the rendered content for the first matching route. Matching is first-match-wins: patterns are checked in object key order.

tsx
import type { PC } from 'preffx';

export const App: PC = (_props, { routes }) => {
    const content = routes({
        '/': () => <div>Home</div>,
        '/:lang?/user/:id': (_, { routeParams }) => (
            <div>User #{routeParams.id} ({routeParams.lang || 'en'})</div>
        ),
        '*': () => <div>Not found</div>
    });

    return (
        <div>
            <a href="/">Home</a>
            <a href="/user/42">User page</a>
            <a href="/ru/user/42">User page (ru)</a>
            <a href="/unknown">Unknown page</a>
            {content}
        </div>
    );
};

Route patterns ​

PatternDescriptionExample match
/usersStatic segment/users
/user/:idRequired parameter (:id)/user/42 → { id: '42' }
/:lang?/homeOptional parameter (?); empty when absent/home → { lang: '' }
/files/*Splat — captures the rest (from the trailing *)/files/a/b → { '*': 'a/b' }
*Catch-all — matches any path/anything

Notes:

  • Route parameters are URI-decoded automatically.
  • A pattern matches a prefix of the pathname: /users also matches /users/42. Use a catch-all or a more specific pattern when you need exact matching.
  • * acts as a wildcard only as the last segment; elsewhere it is treated as a literal.
  • Matched route parameters are available through routeParams.
  • In a nested layout, relative patterns are resolved against the parent route's matched path.

Nested routes ​

Call routes() in a parent component; the matched child component is rendered into the returned signal. Route params from the matched pattern are exposed via routeParams and are also available to descendants through context.

Utils summary ​

OptionTypeDescription
defaultURLstring | URLInitial URL (for SSR pass the request URL)
urlReadonlySignal<URL>Current URL, reactive
navigate(url, options?)Navigate to a URL
routes(paths) => signalFirst-match route rendering
routeParamsRecord<string, string>Parameters of the currently matched route

Released under the Apache-2.0 License.