Layouts control the page chrome: whether a sidebar, table of contents, or full-width content area appears. Set the layout per page in frontmatter or per collection in sarde.yaml. Templates render the HTML for each layout using Go's html/template engine.
Layout types
Sarde ships eight layout types. Each determines which structural elements appear on the page.
| Layout | Sidebar | TOC | Content width | Use for |
|---|---|---|---|---|
default |
no | no | Standard | Blog posts, standalone pages |
docs |
yes | yes | Standard | Documentation, courses, tutorials |
splash |
no | no | Full width | Landing pages, homepages |
wide |
yes | no | Wider | Media-heavy docs pages |
full |
no | no | Full width | Custom pages, dashboards |
centered |
no | no | Narrow | About pages, legal pages |
split |
no | no | Two equal columns | Comparison pages |
presentation |
no | no | Full width | Full-screen slide decks. See Presentation Layout |
Set the layout in frontmatter:
---title: Aboutlayout: centered---Or set it for an entire collection in sarde.yaml:
collections: docs: layout: docsBlog collections default to default. Docs collections default to docs. All other collections default to default.
Template overlay resolution
When Sarde renders a page, it searches for the template file through a multi-layer lookup chain. The first match wins (most specific takes precedence):
Default-layout pages (5 layers)
layouts/<collection>/single.html(user, collection-specific)themes/<theme>/layouts/<collection>/single.html(theme, collection-specific)layouts/_default/single.html(user, default)themes/<theme>/layouts/_default/single.html(theme, default)- Embedded
_default/single.html(compiled into binary)
Docs-layout pages (8 layers)
Docs-layout pages insert _docs/ layers between the collection and default layers:
layouts/<collection>/single.htmlthemes/<theme>/layouts/<collection>/single.htmllayouts/_docs/single.htmlthemes/<theme>/layouts/_docs/single.htmllayouts/_default/single.htmlthemes/<theme>/layouts/_default/single.html- Embedded
_docs/single.html - Embedded
_default/single.html
Blog-layout pages (8 layers)
Blog-layout pages follow the same pattern, inserting _blog/ type layers:
layouts/<collection>/single.html(user, collection-specific)themes/<theme>/layouts/<collection>/single.html(theme, collection-specific)layouts/_blog/single.html(user, blog-type)themes/<theme>/layouts/_blog/single.html(theme, blog-type)layouts/_default/single.html(user, default)themes/<theme>/layouts/_default/single.html(theme, default)- Embedded
_blog/single.html - Embedded
_default/single.html
The _blog/ type directory activates for any collection named blog, posts, articles, or news. Collection-name directories (e.g. layouts/posts/) target only that specific collection.
See Blog and Taxonomies for the shipped blog template variants.
Partials
Partials are reusable template fragments. The resolution order (3 layers, first match wins):
layouts/partials/<name>.html(user)themes/<theme>/layouts/partials/<name>.html(theme)- Embedded
partials/<name>.html
Call a partial from a template:
{{ partial "sidebar-extra.html" . }}Override any embedded partial by placing a file with the same name in layouts/partials/.
Components vs. partials
Sarde distinguishes two kinds of reusable template units:
-
Components are engine-owned. Called with
{{ component "Name" . }}, they render structural layout elements (Header, Sidebar, Footer, Search) with safe defaults. If a component is missing, the engine renders nothing rather than erroring. -
Partials are theme-owned. Called with
{{ partial "name.html" . }}, they render content-level fragments (hero sections, blog cards, social links). A missing partial produces a template error.
Override a component by placing a file at layouts/components/<Name>.html. See UI Components for the full list of overridable components.
Custom templates
Create a custom template by placing a file in layouts/ that defines the "content" block. For example, a magazine-style blog post variant at layouts/_blog/single-magazine.html:
{{ define "content" }}<article class="blog-magazine"> <header class="magazine-header"> {{ if .Page.Image }} <img src="{{ .Page.Image }}" alt="{{ .Page.Title }}"> {{ end }} <h1>{{ .Page.Title }}</h1> <p class="magazine-subtitle">{{ .Page.Description }}</p> </header> <div class="magazine-body"> {{ .Page.Content }} </div></article>{{ end }}→ A magazine-style layout with a large header image, title, and subtitle above the post body.
Templates receive a RouteData object as their context (.), which includes .Page, .Site, .Sidebar, .Breadcrumbs, .Translations, and other layout data. See Route Data for every field and Template API for how the pieces fit together.
Assign the template to a post in frontmatter. The template field is a path relative to the layouts directory, without .html:
---title: "Introduction to Photosynthesis"template: blog/single-magazine---Placing the file in _blog/ makes it available to all blog-type collections (blog, posts, articles, news). To target only a collection named posts, place it in layouts/posts/single-magazine.html instead.
Template naming conventions
Template variant files use a hyphenated suffix: {kind}-{variant}.html.
| Pattern | Example | Meaning |
|---|---|---|
single.html |
_blog/single.html |
Default single-page template for the type |
single-{variant}.html |
_blog/single-cover.html |
Named variant of the single-page template |
list.html |
_blog/list.html |
Default list template for the type |
list-{variant}.html |
_blog/list-grid.html |
Named variant of the list template |
Underscore-prefixed directories (_blog/, _docs/, _default/) are shared type directories; non-prefixed directories (blog/, posts/) are collection-specific and take priority. The template frontmatter field omits the .html extension; the engine appends it during resolution.
See Template Functions for all available functions, and UI Components for the component registry.