Askr
Routing & Data

Definitions and Layouts

Use definitions and layouts with the current published Askr packages.

  • @askrjs/askr0.0.59

How to use definitions and layouts

Start with this complete definitions and layouts shape, then replace the example data and application service with your own.

  1. Import the published @askrjs/askr entrypoint.
  2. Keep definitions and layouts configuration next to the component, route, or server composition root that owns it.
  3. Handle pending, unavailable, cancellation, and failure states, then verify the production path.
const registry = createRouteRegistry(() => {
  group({ layout: AppLayout }, () => {
    route('/', HomePage);
    route('/projects/:projectId', ProjectPage);
  });
});

Route definitions

`route(path, Component, options?)` is the building block for a single URL: it returns a typed `RouteRef` you can later pass to `to()` for building destinations, and it accepts a `RouteOptions` object for loaders, policies, search-param schemas, and metadata. `page(path, Component, fn)` is the nested-route sibling — it declares a route at `path` and opens a child definition scope, so pages under it can add their own sub-routes or a layout. Both infer route params from the path string itself: writing `route('/posts/{slug}', ...)` gives the component a typed `slug: string` prop with no manual generic annotation needed.

Groups and layouts

A layout is just a component with a `children` prop, attached to a group via `GroupHelperOptions.layout` or to a page via the layout argument on `page()`. Askr stores it as a `LayoutScopeRecord` and composes it automatically at render time — you never call the layout component yourself. Layout composition happens outside the page chain: pages inside a group render first through `Outlet`, and the layout wraps that result, so a loading state or error inside a page doesn't require the layout to know anything about it.

Nested pages

`page()` lets a route own child routes: the `fn` argument is a definition callback where you call `route()` or nest further `page()` calls scoped under that parent path. Each nested route contributes to the same `RouteRecord.segments` matching logic, and Askr ranks routes by specificity so a literal segment like `/posts/new` wins over a param segment like `/posts/{id}` when both could match. `index(Component, options?)` fills the special case of "what renders at this path with nothing appended" — the default child when a parent route is visited directly.

Fallback routes

`fallback(Component)` registers the component Askr renders when no other route matches, and it's marked internally with `isFallback: true` on its `RouteRecord` so the router treats it distinctly from an ordinary catch-all. You get exactly one fallback per manifest — it's meant to be your app's 404 page, not a general-purpose wildcard route. If you need a wildcard that still participates in normal matching and layout composition, use a `*` or `{*splat}` path segment on a regular `route()` instead.