Router
A lightweight client-side router with dynamic parameters, wildcard routes, grouped prefixes, middleware pipelines, navigation guards, and full browser history integration. Refresh-safe on any static host — no server rewrites required.
Quick Start
Register routes, add optional middleware, then call Aura.init() to start listening for URL changes.
import Aura from 'aurajs'; // Define routes Aura.route('/', (ctx) => { console.log('Home page'); }); Aura.route('/users/:id', (ctx) => { console.log('User:', ctx.params.id); }); // Add middleware Aura.middleware((ctx) => { console.log('Navigating to', ctx.path); return true; }); // Start the app Aura.init(); // Optional: customize the route query param (default '_r') // Aura.init({ routeParam: 'page' });
URL Encoding
Your app's logical path — /users/42?tab=posts — is what route(),
navigate(), ctx.path, and currentPath all work with.
In the browser's address bar that path is stored as a query parameter on the page you loaded:
// Logical path your app navigates to: /users/42?tab=posts // What actually appears in the address bar: /?_r=/users/42&tab=posts
This means a user who refreshes, bookmarks, or shares any deep link still hits the real file
your host is serving (/index.html) — no server rewrite rules, no 404s on
refresh, no hosting configuration. Works identically on GitHub Pages, S3, Vercel, Netlify,
Cloudflare Pages, or any static file server.
The query parameter is _r by default. Override it via Aura.init():
Aura.init({ routeParam: 'page' }); // => /?page=/users/42&tab=posts
Hash fragments (#section) are preserved on the browser URL for native anchor
scrolling. Your own ?foo=bar query string is merged alongside _r
and parsed into ctx.query as usual — you never see the encoding yourself.
Types
RouteContext
Every route handler and middleware receives a RouteContext object.
| Property | Type | Description |
|---|---|---|
| path | string | The full matched path including query string. |
| params | Record<string, string> | Dynamic route parameters (e.g. :id). |
| query | Record<string, string> | Parsed query-string key/value pairs. |
| name | string | undefined | Optional route name, if one was provided. |
route() core
Register a route with a path pattern and a handler function. Supports dynamic segments (:param) and wildcard catch-all (/*).
| Param | Type | Description |
|---|---|---|
| path | string | URL pattern. Use :param for dynamic segments, /* for catch-all. |
| handler | RouteHandler | Callback (ctx: RouteContext) => void | Promise<void> invoked when the path matches. |
| name | string | Optional name used with urlFor() for reverse-routing. |
// Static route Aura.route('/about', (ctx) => { document.querySelector('#app').innerHTML = '<h1>About</h1>'; }); // Dynamic parameter Aura.route('/posts/:slug', (ctx) => { console.log(ctx.params.slug); }); // Named route Aura.route('/users/:id', showUser, 'user-detail'); // Wildcard catch-all Aura.route('/files/*', (ctx) => { console.log(ctx.params.wildcard); // everything after /files/ });
group() organization
Group multiple routes under a shared URL prefix. The callback receives a scoped router object with a route() method that automatically prepends the prefix.
| Param | Type | Description |
|---|---|---|
| prefix | string | URL prefix prepended to every route in the group (e.g. /admin). |
| fn | Function | Callback that receives a scoped router { route } for registering sub-routes. |
Aura.group('/admin', (r) => { // Registers /admin/dashboard r.route('/dashboard', (ctx) => { console.log('Admin dashboard'); }); // Registers /admin/users/:id r.route('/users/:id', (ctx) => { console.log('Admin user', ctx.params.id); }, 'admin-user'); });
navigate() core
Programmatically navigate to a path. Pushes a new entry onto the browser history stack. Respects the beforeLeave guard and runs all registered middleware before executing the route handler.
| Param | Type | Description |
|---|---|---|
| path | string | The target URL path (e.g. /users/42). |
// Navigate with history push await Aura.navigate('/dashboard'); // Navigate with query params await Aura.navigate('/search?q=aura&page=1');
redirect() core
Navigate to a path without pushing a new browser history entry. Useful for post-login redirects or replacing the current page silently.
| Param | Type | Description |
|---|---|---|
| path | string | The target URL path to redirect to. |
// Redirect without adding to history await Aura.redirect('/login');
middleware() guard
Register a global middleware function. Middleware runs in registration order before every route handler. Return true to continue or false to abort navigation (sets page state to 'error').
| Param | Type | Description |
|---|---|---|
| fn | Middleware | Function receiving a RouteContext. Return false to block navigation. |
// Auth guard middleware Aura.middleware((ctx) => { if (ctx.path.startsWith('/admin') && !isLoggedIn()) { Aura.redirect('/login'); return false; } return true; }); // Logging middleware Aura.middleware((ctx) => { console.log(`[Router]`, ctx.path); return true; });
beforeLeave() guard
Register a navigation guard that fires before leaving the current route. Only applies when using navigate(). Return false to cancel navigation (e.g. for unsaved-changes prompts).
| Param | Type | Description |
|---|---|---|
| fn | Function | Guard receiving the current path (from) and the target path (to). Return false to cancel. |
Aura.beforeLeave((from, to) => { if (hasUnsavedChanges) { return confirm('Discard unsaved changes?'); } return true; });
errorPage() error
Register a handler for unmatched routes (404 pages). Called when no registered route pattern matches the requested path.
| Param | Type | Description |
|---|---|---|
| handler | RouteHandler | Callback invoked with a context whose params is empty and path is the unmatched URL. |
Aura.errorPage((ctx) => { document.querySelector('#app').innerHTML = ` <h1>404</h1> <p>Page not found: ${ctx.path}</p> `; });
refresh() core
Re-run the handler for the current route without changing the URL or pushing history. Useful after data updates when you need to re-render the current page.
This method takes no parameters.
// Re-execute the current route handler await Aura.refresh();
urlFor() utility
Generate a logical path from a named route. Replaces :param placeholders with the provided values. Returns null if no route with the given name exists. The returned value is the logical path (e.g. /users/42) — pass it to navigate() or use it as an <a href>; the router handles URL encoding automatically.
| Param | Type | Description |
|---|---|---|
| name | string | The name assigned when the route was registered. |
| params | Record<string, string> | Optional map of parameter names to values to interpolate into the path. |
// Register a named route Aura.route('/users/:id/posts/:postId', handler, 'user-post'); // Generate the URL const url = Aura.urlFor('user-post', { id: '42', postId: '7' }); // => "/users/42/posts/7" // Unknown name returns null Aura.urlFor('nope'); // => null
back() utility
Navigate back one entry in the browser history. Equivalent to history.back().
This method takes no parameters.
Aura.back();
forward() utility
Navigate forward one entry in the browser history. Equivalent to history.forward().
This method takes no parameters.
Aura.forward();
pageState getter
Read-only getter returning the current page lifecycle state. The router automatically transitions through these states during navigation.
| Value | Meaning | |
|---|---|---|
| 'idle' | No navigation has occurred yet. | |
| 'loading' | A route handler is currently executing. | |
| 'loaded' | The route handler completed successfully. | |
| 'error' | The handler threw, middleware blocked, or no route matched (404). |
if (Aura.pageState === 'loading') { showSpinner(); }
currentPath getter
Read-only getter returning the full path (including query string) of the most recently handled route.
console.log(Aura.currentPath); // e.g. "/users/42?tab=posts"
navigationHistory getter
Read-only getter returning a copy of the internal navigation history array. Each entry records the path, extracted params, and a timestamp.
HistoryEntry
| Property | Type | Description |
|---|---|---|
| path | string | The full navigated path. |
| params | Record<string, string> | Extracted route parameters. |
| timestamp | number | Unix timestamp (ms) of when the navigation occurred. |
const history = Aura.navigationHistory; console.log('Pages visited:', history.length); console.log('Last page:', history[history.length - 1].path);
Emitted Events
The router emits the following events via the Aura event bus. Subscribe with Aura.on().
| Event | Payload | Description |
|---|---|---|
| route:change | RouteContext | Fired after a route handler completes successfully. |
| route:error | { path, error } | Fired when a route handler throws an exception. |
| route:notFound | { path } | Fired when no registered route matches the path (404). |
| route:stateChange | PageState | Fired whenever the page state transitions. |
Aura.on('route:change', (ctx) => { console.log('Navigated to', ctx.path); }); Aura.on('route:notFound', ({ path }) => { console.log('404:', path); });