Routing
pnpm add @ramonda/router
Two pieces. Router owns the route state; RouteOutlet renders whichever route matches.
import { Component, Host } from "@ramonda/core";
import { Router, RouteOutlet, createRoutes } from "@ramonda/router";
const routes = createRoutes({
"/": <Home />,
"/players/:id": <Player />,
"*": <NotFound />,
});
@Host("div")
export class App extends Component {
router = this.use(Router);
render() {
return (
<div className="app">
<NavBar />
<RouteOutlet routes={routes} />
</div>
);
}
}
pathname/routing
searchParams(none)
→ State→ Lists→ back here, with a query
Reads are per key: a component reading only pathname is not re-rendered when the query changes.
That demo is reading the router of this site — the documentation you are looking at is a Ramonda app, so the values are real.
Router is a hook, not a component
This is the design decision worth understanding, because it is not what other frameworks do.
A <Router> component would have to be an element — Ramonda is 1-1 — so it would wrap your
whole app in a node you did not ask for. And it could not be the thing that renders the matched
route and the thing that wraps the nav bar, because those are different positions in the tree.
So the two jobs are split. Router is a hook on your app root: it owns the store, publishes it
to the subtree as context, and adds no element. RouteOutlet is a component that renders the
match, and it sits wherever the routed content belongs.
That split is what makes chrome around the outlet work. A nav bar beside the outlet keeps its state across navigation, because nothing above the outlet is swapped:
<div>
<NavBar /> {/* not remounted on navigation */}
<RouteOutlet routes={routes} />
</div>
createRoutes — call it once
const routes = createRoutes({ "/": <Home />, "*": <NotFound /> });
At module scope, not inside render(). It compiles each pattern to a regex once, and the stable
object identity lets RouteOutlet skip work when its parent re-renders.
"*" is the fallback for a path that matches nothing. It has no URL of its own — for a real 404
page on a static host, render one explicitly at the path your host expects.
Only one Router
Mounting a second one while the first is live throws. The store is the single source of truth for the URL, and two of them would disagree the moment either navigated.
The check counts live instances rather than latching, so unmounting the first and mounting another — a test, a hot reload — works.
Next
- Links — navigating without losing what a real
<a>gives you.