I was recently building a small personal finance tracker for my family and needed a plain, lightweight SPA router.
Most traditional SPA routers end up reimplementing a lot of plumbing — click interception, scroll restoration, and focus management — on top of the old History API. This happens because the History API only natively gives you pushState and a popstate event. The rest is on you (or your router library).
However, the Navigation API, which reached Baseline earlier this year, already handles most of that natively in modern browsers. So instead of rebuilding that plumbing again, I decided to write a thin router that delegates the heavy lifting to the browser and only keeps what a router actually has to own: matching, guards, and an async navigation state machine.
Here is the result: isorouter.
The Numbers & Architecture
It features a ~1.8KB gzipped core with zero dependencies.
The interception, matching, guards, lazy-loading, and async-commit state machine live in a pure-TypeScript core. On top of that, there are thin adapters (~0.5KB each) that bind that core into Svelte 5, React, and Vue 3.
What it does
- Compile-time type-safe navigation: Routes are declared
as const, sonavigate()calls with typos will fail to compile. - Nested layouts: Fully supported out of the box.
- Async navigation guards: Includes abort signals to handle complex data fetching or auth checks before a route commits.
- Lazy loading: Only load the code you need.
What it deliberately doesn't do
SSR, data loaders/actions, and search-param parsing.
Those features belong to a meta-framework (like Next, Nuxt, or SvelteKit) or your own specialized components. This project strictly stays a thin routing layer over the browser platform, not a meta-framework competitor.
Caveat upfront
The Navigation API is Newly Baseline, not yet Widely available across older browser engines. If you support older versions, you will need a polyfill (like @virtualstate/navigation).
🤝 Missing your favorite framework?
Because the core is completely decoupled, wrapping it is super easy. If you use Solid, Preact, Alpine, or anything else and want to build an adapter — open an issue or drop a PR. I'm very open to the community and would love to build them together!
- 📚 Documentation: https://pidkhvatylin-my.github.io/isorouter
- 🐙 GitHub: https://github.com/pidkhvatylin-my/isorouter
This is my first real open-source release, currently running in production in my own app. I would genuinely appreciate any feedback — especially if anyone else has tried building routing directly on the Navigation API and hit edge cases I haven't found yet!