Layouts

Document chrome, layout selection and the render order.

Updated 2 min read

A layout is a module in app/layouts that exports layout. It receives the rendered page as slot.

module RootLayout {
  use Cataract;

  proc layout(ctx: Context, slot: string, ref meta: PageMeta): string {
    var h = new MarkupBuilder();

    h.open("header");
    h.el("a", "Home", "href", "/");
    h.close();

    h.open("main");
    h.raw(slot);
    h.close();

    return h.done();
  }
}

Selection

A layout is named by its file: app/layouts/root.chpl is root. A page selects one with a module-level param:

param layout = "docs";

Pages default to root, and a project with pages must have a root layout — the scanner reports its absence as a build error rather than letting chpl fail on a missing symbol.

Render order

page  ->  layout  ->  document shell

Layouts run after the page and before the shell, which means a layout can still set fields on meta: a canonical URL derived from ctx.path(), a title suffix, a body class derived from the section being viewed. This wiki does all three in one layout.

meta.title = SiteMeta.pageTitle(meta.title);
if meta.canonical.isEmpty() then meta.canonical = SiteMeta.canonical(ctx.path());
meta.bodyClass = sectionClass(ctx.path());

Two layouts, one shell

Multiple layouts are ordinary: a documentation layout with a sidebar, a marketing layout without one. Both end at the same document shell, so <head>, lang, stylesheet links and the client runtime tag stay in one place.

A layout may itself declare an island, in which case every page using that layout ships the client runtime — which is how a search box lands on every page of a site without each page opting in.