A client-side router library using Navigation & URLPattern
This router intercepts same-origin navigations and resolves them to registered route modules. Each module can return content in multiple native formats (e.g. Response, Document, Element), allowing flexibility without imposing rendering constraints.
Key characteristics:
- Native Navigation API (
navigation) - Route-to-module mapping via dynamic
import() - Direct DOM updates (no diffing layer)
- Supports HTML streaming via
Response - Built-in metadata handling (title, description, styles)
- Optional preload observation
- Abort-safe lifecycle with
AbortControllerandDisposableStack
Important
This requires the Navigation API, which is Baseline 2026.
It also creates a Trusted Types Policy, where supported,
labeled "aegis-atlas#html" for handling HTML responses without sanitizer restrictions.
Tip
Route module specifiers can use bare specifiers like @acme/blog. These can be resolved via an import map, for example:
<script type="importmap">
{
"imports": {
"@acme/blog": "https://cdn.example.com/acme-blog/index.js"
}
}
</script>This allows modules to be loaded from a CDN without changing route definitions.
This module is intended to be used directly in modern browser environments.
import { init } from '@aegisjsproject/atlas';No dependencies required.
Each route resolves to a module with the following shape:
export default async function handler(request, context) {
return new Response('<h1>Hello</h1>', {
headers: { 'Content-Type': 'text/html' }
});
}
export const title = 'Page Title';
export const description = 'Page description';
export const styles = new CSSStyleSheet();default(required)- Function:
(Request, RouteContextObject) => HandlerResult - Or static value:
HandlerResult
- Function:
title(optional)description(optional)styles(optional:CSSStyleSheetor array)
Handlers may return:
Response(must betext/html)HTMLDocumentElementDocumentFragmentURL(triggers navigation)
Each handler receives a context object:
{
result, // URLPatternResult
params, // extracted route params
stack, // DisposableStack
controller, // AbortController
signal, // AbortSignal
type, // navigation type
url, // URL instance
state, // navigation state
info, // navigation info
timestamp // performance timestamp
}init({
'/': '/routes/home.js',
'/users/:id': '/routes/user.js'
'/posts/:year(\\d{4})/:month(\\d{2})/:day(\\d{2})/:slug': '@acme/blog',
'/product/:sku': '@acme/store/product',
}, {
root: 'app',
preload: true
});root: Element or element ID where content is renderedpreload: Enable preload observationsignal: OptionalAbortSignalfor teardown
import { navigate, back, forward, reload } from './router.js';
navigate('/about');
back();
forward();
reload();Wait for navigation completion:
import { whenLoaded } from './router.js';
await whenLoaded();Navigation is intercepted only if:
event.canInterceptis true- URL is same-origin
- Triggering element does not have
.no-router
- Must be
text/html - Parsed via
Document.parseHTMLUnsafe - Re-processed as
HTMLDocument
- Updates:
document.title- meta description
- root content
- Directly replaces root children
- Triggers navigation
setRoot('app');
// or
setRoot(document.getElementById('app'));If root is <body>, full body is replaced.
If root is an element with id, only matching subtree is replaced.
Route modules can define:
title→ updatesdocument.titledescription→ updates all matching meta tags:name="description"og:descriptiontwitter:description
styles→ appended todocument.adoptedStyleSheets
- Automatically determines method (
GETorPOST) - Submits
FormDatawhen applicable - Uses
RequestAPI for consistency
Each navigation:
- Uses
AbortController - Combines signals via
AbortSignal.any - Cleans up via
DisposableStack
Handlers should respect context.signal where applicable.
If supported, a Trusted Types policy is used to safely pass HTML into:
Document.parseHTMLUnsafe(...)This ensures CSP compatibility without stripping critical markup like:
<iframe>- inline event handlers
- form attributes
export default async function(request, { params }) {
return new Response(`
<h1>User ${params.id}</h1>
`, {
headers: { 'Content-Type': 'text/html' }
});
}
export const title = 'User Profile';
export const description = 'User details page';- Only
text/htmlresponses are supported forResponse - Non-matching routes fall back to
fetch() - Errors during routing are surfaced via
reportError - Designed for modern browsers with Navigation API support
This router provides a low-level, high-control alternative to framework routers by:
- Eliminating abstraction layers
- Leveraging native platform APIs
- Supporting flexible content types
- Maintaining strict control over navigation lifecycle
Intended for environments where performance, control, and minimal overhead are priorities.