Guide & Best Practices

Router works best when the URL is treated as the source of truth for navigation, filters, tabs, and shareable UI state. Keep route declarations close to the layout they control, then use the JavaScript API only for behavior that cannot be expressed cleanly in HTML.

Start With Declarative Routes

For most pages, use <page-route>, <page-link>, and <page-redirect> directly in the document. This keeps the app understandable from the HTML structure alone.

html
1<nav>2    <page-link path="/" title="Home">Home</page-link>3    <page-link path="/projects" title="Projects">Projects</page-link>4    <page-link path="/settings" title="Settings">Settings</page-link>5</nav>6 7<main>8    <page-route path="/" src="./pages/home.html"></page-route>9    <page-route10        path="/projects"11        exact="false"12        src="./pages/projects.js"13    ></page-route>14    <page-route path="/settings" src="./pages/settings.html"></page-route>15    <page-route path="/404">Page not found.</page-route>16    <page-redirect path="/404"></page-redirect>17</main>

Use Nested Routes For Layouts

Parent routes are useful for sections that share navigation, headings, or route data. Child paths extend the nearest parent route.

html
1<page-route path="/projects/:projectId" exact="false">2    <header>3        <h1>Project <page-data param="projectId">unknown</page-data></h1>4        <page-link path="$/overview">Overview</page-link>5        <page-link path="$/activity">Activity</page-link>6        <page-link path="$/settings">Settings</page-link>7    </header>8 9    <page-route path="/overview" src="./projects/overview.js"></page-route>10    <page-route path="/activity" src="./projects/activity.html"></page-route>11    <page-route path="/settings" src="./projects/settings.js"></page-route>12    <page-redirect path="$/overview" type="always"></page-redirect>13</page-route>

Use Query Routes For UI State

Use <page-route-query> when the view is still the same page but a query value should choose a tab, drawer, filter, or modal.

html
1<page-link search="panel=details" keep-current-search>Details</page-link>2<page-link search="panel=activity" keep-current-search>Activity</page-link>3 4<page-route-query key="panel" value="details">5    <h2>Details</h2>6</page-route-query>7 8<page-route-query key="panel" value="activity" src="./panels/activity.html">9    <p slot="loading">Loading activity...</p>10</page-route-query>

Prefer component For Typed Apps

If you are rendering routes from Markup or Web Component code, the component property avoids string-based dynamic imports and gives bundlers a direct reference.

javascript
1import { html } from '@beforesemicolon/web-component'2import HomePage from './pages/HomePage.js'3import ProjectPage from './pages/ProjectPage.js'4 5export const routes = html`6    <page-route path="/" component="${HomePage}"></page-route>7    <page-route8        path="/projects/:projectId"9        component="${ProjectPage}"10    ></page-route>11`

Register Guards Before Navigation

Guards run before route listeners and route components are notified. Register them during application startup, before rendering protected routes or triggering navigation.

javascript
1import {2    registerGlobalGuard,3    registerRouteGuard,4} from '@beforesemicolon/router'5 6registerGlobalGuard((pathname) => {7    if (pathname.startsWith('/account') && !session.currentUser) {8        return '/login'9    }10 11    return true12})13 14registerRouteGuard('/admin/:section', async () => {15    return (await session.hasRole('admin')) || '/unauthorized'16})

Keep 404s Last

<page-redirect> checks the routes that have been registered. Put fallback redirects after the valid <page-route> declarations they depend on.

html
1<page-route path="/">Home</page-route>2<page-route path="/docs" exact="false">Docs</page-route>3<page-route path="/404">Not found</page-route>4 5<page-redirect path="/404"></page-redirect>

Choose History Or Hash Routing Early

History routing gives clean URLs and is the default. Hash routing is useful when your host cannot rewrite unknown paths back to index.html.

javascript
1import { setRoutingMode } from '@beforesemicolon/router'2 3setRoutingMode('hash')

Production Checklist

edit this doc