Concorde documentation (crawl) · interactive version

Concorde functional component — Router. sonic-router watches document.location (pathname + hash) and renders the matching view. Doc ID: core/components/functional/router/router. Keywords: Concorde, supersoniks, core/components/functional/router/router, router, Router, functional component, sonic-router, web component, document.location, .routes, .items, fallback, , pathname + hash, #home, #…/router.md/router, #…/router#home, href. URL: https://concorde.supersoniks.org/crawl/core/components/functional/router/router.html.

Router

sonic-router watches document.location (pathname + hash) and renders the matching view.

From a Lit parent, pass a .routes map (property binding — same rule as .items on list): keys are path patterns, values are render functions. Use fallback when nothing matches.

Legacy HTML <template data-route="…"> remains for hosts without Lit — HTML integration.

Static routes (no parameters)

Route keys are matched against pathname + hash. A simple hash route #home matches when the location contains that segment.

On the doc site, the page URL is already a hash (../../../../…/router.html#router). Demos append a second hash for in-page routes (#…/router#home), use href + autoActive="strict" on sonic-button for the active state, and history.replaceState on click so markdown is not reloaded (setDocsDemoSubHash in src/docs/docs-location.ts).

@state()
private routes = {
  "#home": () => html`<div>Home</div>`,
  "#about": () => html`<div>About</div>`,
  fallback: () => html`<div>Not found</div>`,
};

html`
  <sonic-button href="#home">Home</sonic-button>
  <sonic-router .routes=${this.routes}></sonic-router>
`;
Key When it runs
"#home", "#about", … RegExp or url-pattern test succeeds on current location
fallback No other route matched (not an attribute — a key on the same object)

Routes with parameters

Two styles (see router.demo.ts and docs-router-params-demo):

Url-pattern (:name)

Key uses :param segments. The render function receives an object { param: string }.

"#couleur/:id": ({ id }) => html`<p>Colour id: ${id}</p>`,

RegExp (capturing groups)

Key is a RegExp string with (\d+) / (\w+) groups. The render function receives an array of captured strings (in order).

"#products/(\\d+)/(\\w+)": ([productId, slug]) =>
  html`<p>Product ${productId}, slug ${slug}</p>`,

With parameters you usually render data directly in Lit (${id}). The old <template data-route> + dataProviderExpression pattern scoped a dataProvider for data-bind / fetch children — prefer @subscribe or explicit props when using .routes.

.routes binding

Always use .routes=${…} in Lit templates: route handlers are functions and must be set as properties, not HTML attributes.

Optional attributes

Attribute Role
basePath Prefix for pattern matching (default allows optional leading segments)
fallBackRoute If set and no template/route matches, navigates to this URL (redirect). Distinct from routes.fallback which only renders content

sonic-redirect

Separate component: redirect when data appears on a publisher (login steps, wizards). Not part of the .routes map.

<sonic-redirect to="./router.html#router#data-is-set" dataProvider="stupid-data-set-id" onData="theData"></sonic-redirect>
    <div class="flex gap-2 mb-4" formDataProvider="stupid-data-set-id">
      <sonic-button radio name="theData" value="Some Data" size="xs">
        Enter data
      </sonic-button>
      <sonic-button radio name="theData" value="" href="javascript:history.back();" size="xs">
        Delete the data and do a history.back()
      </sonic-button>
    </div>

Example: combine with .routes and submit for login / logout / profile steps.

Package demo

sonic-router-demo (router.demo.ts) — home, user profile (#user/:id/:slug), products RegExp, fallback 404.