Skip to content

Routing

@whisq/router provides client-side routing built on signals. Routes are reactive — when the URL changes, the matched component renders automatically.

Install the router package:

Terminal window
npm install @whisq/router

Create a router with your route configuration:

import { createRouter, RouterView, Link } from "@whisq/router";
import { div, h1, p, mount } from "@whisq/core";
const Home = () => div(h1("Home"), p("Welcome to Whisq"));
const About = () => div(h1("About"), p("Learn more about Whisq"));
const router = createRouter({
routes: [
{ path: "/", component: Home },
{ path: "/about", component: About },
],
});
mount(
div(
div(
Link({ href: "/", router }, "Home"),
Link({ href: "/about", router }, "About"),
),
RouterView(router),
),
document.getElementById("app"),
);

RouterView renders the component that matches the current URL. Link handles navigation without a full page reload.

Use :param syntax for URL parameters:

import { createRouter, RouterView } from "@whisq/router";
import { component, div, h1, p } from "@whisq/core";
const UserPage = component((props: { params: { id: string } }) =>
div(
h1(() => `User ${props.params.id}`),
p("User profile page"),
)
);
const router = createRouter({
routes: [
{ path: "/users/:id", component: UserPage },
],
});

Multiple params work too: /users/:userId/posts/:postId.

The router exposes a reactive current signal:

const router = createRouter({ routes: [...] });
// Current route state (reactive)
router.current.value.path; // "/users/42"
router.current.value.params; // { id: "42" }
router.current.value.query; // { sort: "name" } from ?sort=name

Use it in your UI:

import { div, span } from "@whisq/core";
div(
span(() => `Current path: ${router.current.value.path}`),
);

Navigate from code using router.navigate():

import { button } from "@whisq/core";
button({
onclick: () => router.navigate("/dashboard"),
}, "Go to Dashboard");

Catch unmatched URLs with a wildcard * route:

import { div, h1, p } from "@whisq/core";
const NotFound = () =>
div(h1("404"), p("Page not found"));
const router = createRouter({
routes: [
{ path: "/", component: Home },
{ path: "/about", component: About },
{ path: "*", component: NotFound },
],
});

Check router.current to style the active link:

import { Link } from "@whisq/router";
Link({
href: "/about",
router,
class: () =>
router.current.value.path === "/about" ? "nav-link active" : "nav-link",
}, "About");

Query strings are automatically parsed and available on the route state:

// URL: /search?q=Whisq&page=2
router.current.value.query; // { q: "Whisq", page: "2" }

Navigate with query params:

router.navigate("/search?q=signals&page=1");
  • Components — Building the page components
  • Data Fetching — Load data based on route params
  • SSR — Server-render routed pages