Layouts are the foundation of every OrbLayout site. Define your HTML boilerplate once, then reuse it across every page โ automatically.
Without layouts, every HTML page repeats the same boilerplate:
<!-- You copy-paste this into EVERY page -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>My Site</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<header>...</header> <!-- Same on every page -->
<nav>...</nav> <!-- Same on every page -->
<!-- Only THIS part changes -->
<main>
<h1>Hello World</h1>
</main>
<footer>...</footer> <!-- Same on every page -->
</body>
</html>
With 10 pages, that's 10 copies of the same header, nav, footer, and meta tags. Change the nav? Edit 10 files. ๐ฉ
Layouts solve this. Write the shell once. Each page only provides its unique content.
A layout file lives in the layouts/ folder and uses the .layout extension. It's just HTML with a special placeholder: {{ content }}.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ title }}</title>
</head>
<body>
<header>
<h1>My Website</h1>
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
</nav>
</header>
<main>
{{ content }}
</main>
<footer>
<p>© 2026 My Website</p>
</footer>
</body>
</html>
{{ content }} is the magic placeholder. Whatever a page puts inside its <content> block will replace this marker.
In your .orb page, reference the layout with <layout src="..."> and put your page content inside <content>:
<layout src="main.layout">
<content>
<h2>Welcome Home!</h2>
<p>This is the home page.</p>
</content>
</layout>
<layout src="main.layout">
<content>
<h2>About Us</h2>
<p>We build cool stuff.</p>
</content>
</layout>
Both pages share the same layout. The only difference is what's inside <content>.
This is the home page.
© 2026 My Website
Notice the {{ title }} in the layout? You can populate it using a data block in your page:
<script data>
({
title: "Home โ My Website"
})
</script>
<layout src="main.layout">
<content>
<h2>Welcome Home!</h2>
</content>
</layout>
The title from the data block flows into the layout's <title>{{ title }}</title>. This is how each page gets a unique browser tab title.
Data blocks are covered in depth in Lesson 4. For now, just know they pass data to the layout.
Sometimes a layout needs multiple content areas, not just one. Named slots make this possible.
<!DOCTYPE html>
<html>
<body>
<div class="layout">
<aside class="sidebar">
{{ sidebar }}
</aside>
<main class="content">
{{ content }}
</main>
</div>
</body>
</html>
<layout src="docs.layout">
<content>
<h1>Documentation</h1>
<p>Welcome to the docs.</p>
</content>
<slot:sidebar>
<nav>
<a href="#intro">Introduction</a>
<a href="#api">API Reference</a>
<a href="#faq">FAQ</a>
</nav>
</slot:sidebar>
</layout>
<slot:sidebar> fills the {{ sidebar }} placeholder. <content> fills {{ content }}. You can create as many named slots as you need.
Rules: The slot name after <slot: must match the {{ variableName }} in the layout. The closing tag must match too: </slot:sidebar>.
You're not limited to one layout! Create different layouts for different page types:
layouts/
โโโ main.layout โ Standard pages (home, about)
โโโ docs.layout โ Documentation (sidebar + content)
โโโ blog.layout โ Blog posts (author, date, content)
โโโ landing.layout โ Landing pages (full-width, no nav)
Each page chooses its layout via src="...":
<layout src="main.layout">
...
</layout>
<layout src="blog.layout">
...
</layout>
You should now understand:
{{ content }} as a placeholder<layout src="..."><content>...</content><slot:name>) create multiple content areas{{ title }} in layouts get filled by page data blocks