Guide / 06
Layouts & Nesting
Layouts allow you to define shared HTML structures (navbar, sidebar, footer) that wrap child pages. They are automatically chained based on the directory hierarchy.
Creating a layout
The pages/@layout.stew file:
<goscript>
import "os"
import "github.com/ZiplEix/stew/sdk/live"
</goscript>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title>My App</title>
</head>
<body>
<nav>...Navbar...</nav>
<slot /> <!-- The page content is inserted here -->
{{ if os.Getenv("STEW_DEV") == "true" }}
{{ raw(live.InjectScript()) }}
{{ end }}
</body>
</html>
<slot />: The <slot /> tag is the injection point for child content. Without it, the page would not be displayed within the layout.
Nested Layouts
Each subfolder can have its own @layout.stew. Layouts chain from the root to the leaf:
Rendering of GET /guide/installation:
pages/@layout.stew β HTML shell (DOCTYPE, head, body)
βββ pages/guide/@layout.stew β Navigation sidebar
βββ pages/guide/installation/@page.stew β Content
The generated router automatically creates the closure chain:
pages.Layout(w, data, func() {
stew_pages_guide.Layout(w, data, func() {
stew_pages_guide_installation.Page(w, data)
})
})
Go Signature of a Layout
The compiler generates for @layout.stew:
func Layout(w io.Writer, data stew.PageData, slot func()) {
// HTML rendering before the slot
w.Write([]byte(`...`))
// Slot injection
if slot != nil {
slot()
}
// HTML rendering after the slot
w.Write([]byte(`...`))
}
PageData in Layouts
The layout receives the same data stew.PageData object as the page. It can therefore access the current URL to highlight the active link in a navigation:
<goscript>
getLinkClass := func(target string) string {
if data.URL == target {
return "font-bold text-amber-600"
}
return "text-stone-600"
}
</goscript>
<nav>
<a href="/" class="{{ getLinkClass("/") }}">Home</a>
<a href="/blog" class="{{ getLinkClass("/blog") }}">Blog</a>
</nav>