Building a multi-page site

One playground can serve a whole site. Each page is a <template> exported with o: and hidden from the deployed root with edge:redact, shared styles and scripts are top-level exports, and a preview frame shows the page you are editing. These docs use the same layout.

How it works

A <template> is inert: nothing in it renders, scripts do not run and custom elements do not upgrade. That is why a template can hold a whole page, including <meta>, <title>, <link> and <script src>. Exported with o:, the innerHTML of the template becomes the file. On deploy, edge:redact replaces the template in the root with a comment, so the page exists only at its own URL.

The root document

The playground source itself. It becomes the home page at <route>/ and holds the shared assets, the pages and the preview frame.

Shared assets

A top-level <style o:=.css> and a top-level <script o:=.js>, linked from every page.

Pages

One <template o:=Name.html edge:redact> per page.

Preview frame

A full-viewport <iframe> whose src names one page. It is redacted from the deployed root.

Building the site

A two-page site

A home page, one more page, a shared stylesheet and a preview of the second page:

html
<meta name=viewport content="width=device-width,initial-scale=1" sync=reload>
<title>My site</title>
<style o:=.css>
  body { margin: 0; font: 1rem/1.5 system-ui; color-scheme: light dark }
  nav  { display: flex; gap: 1rem; padding: 1rem }
</style>
<nav><a href=About.html>About</a></nav>
<h1>My site</h1>

<template o:=About.html edge:redact>
<meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1">
<title>About</title><link href=.css rel=stylesheet>
<nav><a href=./>Home</a></nav>
<h1>About</h1>
</template>

<iframe src=About.html edge:redact style=position:fixed;inset:0;width:100%;height:100%;border:0;background:Canvas></iframe>

In the playground, the frame covers the home page and shows /About.html. After a deploy to the route name, the home page is https://name.rt.ht/ and the second page is https://name.rt.ht/About.html. To see the home page while you edit, delete the frame or point its src elsewhere.

Shared styles and scripts

Export shared assets from the top level of the playground, not from inside a template: a <style o:=.css> and, if you need one, a <script o:=.js>. Every page links them with relative URLs, as the second page above does for the stylesheet. Leading-dot names such as .css and .js are valid file names.

Keep these exports outside templates. In the playground, o: on an element inside a template is ignored, so a stylesheet exported from inside a page does not exist there, and the page body still contains the o: attribute. RTEdge.net does export it. A shared export at the top level behaves the same in both.

The pages of these docs follow this pattern: the same three head lines at the top of every page, ending with the link to .css and the script .js.

Page heads and links

Start each page with <meta charset=utf-8>. RTEdge.net serves exported pages as text/html without a charset, so the meta tag is what tells the browser the encoding. Add a viewport meta and a <title> as in any page.

Link pages with relative URLs and the full file name, and link the home page as ./.

Previewing while you edit

Nothing in a template renders, so the root shows none of your pages. The preview frame fixes that: its src names one export, and the output serves that export live. Change src to preview another page. edge:redact on the frame removes it from the deployed root.

The playground rebuilds exports only when the output reloads in full. Edits inside a template never trigger a reload by themselves, because templates are not inspected for reload triggers, so the preview keeps showing the previous page until you press Load (F5). To avoid that, put sync=reload on any element, usually the viewport <meta>, as the example does: every edit then reloads the output and refreshes every export.

Tip: Any custom element that is not declared sync-safe also makes every edit a full reload. If you declare your page elements with <meta io:sync> so that their edits hot-patch, page exports stay stale until Load (F5).

See Live sync and reloads for how edits reach the output.

What the deploy does

A deploy publishes the same state to every route in Code.D. See Deploying.

PlaygroundRTEdge.net
Template with o:=Page.htmlServed at /Page.html after the next full reload.Published at <route>/Page.html as text/html.
edge:redact on the templateNo effect.The root holds a <!--REDACTED … --> comment that spans the same lines.
Preview frame with edge:redactShows the page.Removed from the root.
o: inside a templateIgnored.Exported.
RTCode attributes in a pageKept in the served body.Stripped: every attribute that starts with i:, o:, io:, edge:, h: or worker:.
Doctype of a pageNone added.<!doctype html> added when a browser navigates to the page.

Tip: Show RTCode attributes in a page as escaped code, never as live markup. Live o:, edge:remove and the other prefixed attributes in a page are processed on deploy.

The WebPDF docs at webpdf.pro/docs/ are a live example of this layout: its root holds one comment per page, and each page is served from its own URL.

What stays public

Everything in a template is published at its URL. The authored source of the deployment, including every redacted template, is readable through ? unless access rules restrict it. Do not keep drafts or private notes in templates. See Keeping secrets out and Restricting access.

Availability

FeaturePlaygroundRTEdge.netNotes
Pages exported from <template>YesYesBoth serve the page at its own URL.
o: inside a templateNoYesKeep shared exports at the top level.
edge:redact and edge:removeNoYesApplied on deploy.
Preview frameYesRedactedRedact or remove the frame so the deployed home page is not covered.
sync=reloadYesNo effectKept in the served HTML as an inert attribute.

See also