Pages & Layouts

Every URL is a page. Layouts wrap page content to eliminate boilerplate. Both support data sources, CSS, JS, and the full template syntax.

Pages

A page maps a URL path pattern to a template. The path field supports URLPattern syntax for dynamic routes:

/                    → exact match
/blog/:slug          → path parameter, available as {{ params.slug }}
/products/:id/reviews

Fields

FieldTypeDescription
idTEXT PKUnique identifier
pathTEXT UNIQUEURL path pattern (supports :param wildcards)
titleTEXTPage title (used in <title> and {{ title }})
layoutTEXTLayout ID (defaults to default)
dataTEXT (JSON)Data sources to resolve
contentTEXTTemplate HTML
metaTEXT (JSON)Key/value pairs for <head> meta tags
head_htmlTEXTRaw HTML injected before </head>
body_htmlTEXTRaw HTML injected before </body>
css / jsTEXTPage-specific CSS / JS
validationTEXT (JSON)Validation rules for params, query, body
handlerTEXTCustom JS handler — bypasses template rendering

SEO: always set a meta description — {"description":"A concise summary."}. Pages without one fail Lighthouse audits.

Layouts

Layouts wrap page content. The seeded default layout renders the HTML shell, navbar, footer, and a <main> landmark. The page body is inserted where the layout template has {{content}}:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>{{ title }}</title>
</head>
<body>
{{ component name:"navbar" }}
<main id="main-content" tabindex="-1">
{{content}}
</main>
{{ component name:"footer" }}
</body>
</html>

Fields

FieldDescription
idLayout identifier referenced by pages (default, docs, ...)
nameHuman-friendly name
dataData sources resolved for every page using this layout
css / jsInjected on every page using this layout
contentShell template with the {{content}} placeholder

Resolution order

When a request matches a page:

  1. Validation rules run first — failures return 404.
  2. If the page has a handler, it takes over the full request/response cycle.
  3. Otherwise, data sources from page + layout + referenced components are collected, deduplicated, and resolved in parallel.
  4. The page template renders, then injects into the layout at {{content}}.

Data source priority: when the same key is defined at multiple levels, page wins over layout, layout wins over component.