Components are named template slots that render layout chrome (headers, sidebars, footers, toggles). Call them from layout templates with {{ component "Name" . }}. They are distinct from shortcodes (invoked from Markdown content) and extensions (::: Markdown syntax).
{{ component "Header" . }}The Header component renders the site title, navigation links, search trigger, version switcher, language switcher, social links, center toggle, and theme toggle. Override any component by placing a same-named .html file in layouts/components/.
Calling a component
Pass the name as a string and the current route data (.) as the second argument:
{{ component "Footer" . }}Each mechanism handles unknown names differently:
| Mechanism | Invoked from | Unknown name behavior |
|---|---|---|
component |
Layout templates | Empty string, no error |
partial |
Layout templates | Error |
| Shortcode | Markdown content | Warning, raw text preserved |
A typo in a component name silently renders nothing. Use {{ dump (component "Name" .) }} during development to verify a component produces output.
Overriding components
Components resolve through three layers. Each layer fully replaces same-named components from the layer below.
| Priority | Layer | Directory |
|---|---|---|
| 1 (lowest) | Embedded | Compiled into the binary (31 default components) |
| 2 | Theme | themes/<name>/layouts/components/ |
| 3 (highest) | Project | layouts/components/ |
Filenames are case-sensitive and use PascalCase: Header.html, not header.html. The filename minus .html must match the component name exactly.
Route data
Every component receives the current route data as ., the same value page templates get. The Key data column below names the fields each component reads; every field is documented in Route Data.
Component reference
All 31 built-in components, alphabetically.
| Name | Purpose | Key data | Called by |
|---|---|---|---|
| Breadcrumbs | Breadcrumb trail with home icon | .Breadcrumbs |
_docs/baseof.html |
| CenterToggle | Centered/wide content width toggle | Static | Header |
| ContentPanel | Content area wrapper | .Page.Content |
Not called by default |
| DraftBanner | Draft page notice with pencil icon | .Page.Draft |
All three baseof templates |
| DocsTabSwitcher | Mobile docs tab dropdown | .IsTabbed, .DocsTabs, .ActiveTab |
Sidebar |
| EditLink | "Edit this page" link | .Page.Params, .Site.EditURL |
_docs/baseof.html, blog singles, _default/single.html |
| FallbackNotice | i18n fallback content notice | .Page.IsFallback |
Both baseof templates |
| Footer | Site footer with links and credits | .Site.Config.Footer.* |
Both baseof templates |
| GlobalNav | Top navigation bar | .GlobalNav.Items |
Header |
| Head | <head> content (meta, styles, scripts) |
.Site.*, .Page.*, .Styles |
Both baseof templates |
| Header | Header chrome, composes 8 sub-components | Multiple | Both baseof templates |
| LabBadge | "Lab N" eyebrow chip above the title | .LabNumber, .LabStepLabel |
_labs/baseof.html |
| LabProgress | Step progress bar reading "Step X of Y" | .LabStepIndex, .LabStepTotal |
_labs/baseof.html |
| LanguageSwitcher | Language dropdown | .AllTranslations, .Lang |
Header |
| LastUpdated | "Last updated" byline | .Page.Updated, theme.date_format |
docs, labs, blog singles, _default/single.html |
| LearningObjectives | Callout listing a lab's objectives | .LearningObjectives |
_labs/baseof.html |
| MobileTableOfContents | Mobile collapsible ToC with progress ring | .Page.Headings |
_docs/baseof.html |
| PageBanner | Frontmatter-driven page banner | .PageBanner |
Both baseof templates |
| PageTags | Tag chips with taxonomy links | .Page.Tags |
_docs/baseof.html, blog singles |
| PageTitle | <h1> with optional icon and description |
.Page.Title, .Page.Sidebar.Icon |
_docs/baseof.html |
| Pagination | Prev/next page links | .Pagination |
_docs/baseof.html |
| Scripts | <script> tags (deferred, inline, module) |
.Scripts, .InlineScripts, .ModuleScripts |
Both baseof templates |
| Search | Search trigger button and dialog modal | .Site.Config.Search.Provider |
Header |
| Sidebar | Docs nav tree (3 levels deep) | .Sidebar, .SidebarCollapsedByDefault |
_docs/baseof.html |
| SiteTitle | Site name/logo link to / |
.Site.Title, .Site.Logo |
Header |
| Social | Social icon links row | .Site.Config.Social |
Header, Footer |
| TableOfContents | Desktop sidebar ToC | .Page.Headings |
_docs/baseof.html |
| TagSidebar | Popular tags widget (top 20) | topTerms "tags" 20 |
Not called by default |
| ThemeToggle | Light/system/dark toggle | Static + i18n labels | Header |
| VersionBanner | Unmaintained/unreleased version notice | .VersionBanner, .Versions |
_docs/baseof.html |
| VersionSwitcher | Version dropdown | .Versions, .VersionLabel |
Header |
Components marked Not called by default are registered and overridable but not wired into the default layout. Add them to a custom layout or component override to use them.
Composition
The docs layout (_docs/baseof.html) calls components in this order:
HeadHeader ├── SiteTitle ├── GlobalNav ├── Search ├── VersionSwitcher ├── LanguageSwitcher ├── Social (if header.social enabled) ├── CenterToggle └── ThemeToggleMobileTableOfContents (if page has headings)Sidebar └── DocsTabSwitcher (if collection is tabbed)ThemeToggle (in sidebar footer)VersionSwitcher (in sidebar footer)LanguageSwitcher (in sidebar footer)TableOfContents (if page has headings)Breadcrumbs (if breadcrumbs exist)DraftBannerFallbackNoticeVersionBannerPageBannerPageTitlePageTags [page content]Pagination (if pagination exists)Footer └── SocialScriptsThe default layout (_default/baseof.html) is leaner: Head, Header, DraftBanner, FallbackNotice, PageBanner, content block, Footer, Scripts. It does not call Breadcrumbs, PageTitle, PageTags, Sidebar, or any ToC component.
Component details
Head
Renders <head> content: viewport and generator meta tags, sitemap link (if search enables it), favicon, an inline window.__SARDE__ config object, the <title> tag, meta description, SEO tags via partial "seo.html", theme styles via themeStyles, per-page stylesheets from .Styles, and per-page head tags from frontmatter head. The <meta charset="utf-8"> declaration is not part of this component: each baseof.html emits it as the first element inside <head> so it stays within the first 1024 bytes of the document. A custom baseof.html must declare it itself.
Header
Composes eight sub-components: SiteTitle, GlobalNav, Search, VersionSwitcher, LanguageSwitcher, Social, CenterToggle, ThemeToggle. Social is gated by header.social (default true). Override Header.html to reorganize or remove any of these elements.
Sidebar
Renders the docs navigation tree up to 3 levels deep using collapsible <details>/<summary> elements. Reads .Sidebar.Root.Children and each node's URL, Label, Icon, IsActive, IsOpen, and HasActive fields. Renders sidebar.badge when present on a nav node's page. Calls DocsTabSwitcher at the top when .IsTabbed is true. Sidebar section open/closed state persists via sessionStorage.
Footer
Renders navigation links from footer.links, a Social component (if social is configured), a copyright line with the site title and current year, optional custom text from footer.text, and a "Made with Sarde" credit (controlled by footer.credits, default true).
Search
Hidden entirely when search.provider is "disabled". Renders a trigger button with a keyboard hint (Ctrl/Cmd+K) and a <dialog> modal containing the search input, results list, filters, and a full-search mode toggle. Scopes results by .Version and .Lang via data-* attributes read by the client-side Orama search script.
PageBanner
Renders when .PageBanner is set via frontmatter banner. Accepts Content (text), Variant (default "note"), and Icon (optional). When no icon is specified, one is auto-selected by variant: tip uses lightbulb, caution uses alert-triangle, danger uses alert-octagon, and all others use info.
PageTags
Renders tag chips when showPageTags returns true (page override, then taxonomies.tags.show_tags config, then true). Each tag links to its term page via termURL and displays the label, icon, and color from its TaxonomyTerm definition.
EditLink
Resolves the "Edit this page" URL in order: a custom string from edit_url in page frontmatter, or site.edit_url joined with the page's relative path. Set edit_url: false in frontmatter to disable the link for a specific page.
Renders <a class="sarde-edit-link edit-link"> containing an inline pencil icon followed by the label. The legacy edit-link class is kept alongside the new one so existing custom CSS keeps working.
Called from the blog, default, and docs layouts, inside the shared page meta row. It renders nothing unless site.edit_url is set, so sites that do not configure it see no change.
site.edit_url must point at the content directory, not the repository root, because the page path appended to it is relative to content/. For a site whose project lives in docs/, that means https://github.com/user/repo/edit/main/docs/content.
TableOfContents and MobileTableOfContents
Both consume .Page.Headings and render anchor links for each heading. Both include a synthetic "Overview" link to #_top. The mobile variant wraps the list in a collapsible <details> element and adds a scroll-progress SVG ring. The desktop variant renders in the sidebar ToC panel. Both are conditionally called only when .Page.Headings is non-empty.
VersionSwitcher and VersionBanner
VersionSwitcher renders a dropdown of all versions from .Versions with the current version label, hidden when .Versions is empty (non-versioned collections). VersionBanner shows an "unmaintained" or "unreleased" notice when .VersionBanner is set, with a link to the latest version. See collections versioning for configuration.
LanguageSwitcher
Renders a language dropdown from .AllTranslations. Hidden on single-language sites (empty .AllTranslations list). Each entry shows the language name, direction indicator for RTL languages, and a fallback badge when the translation is a fallback page.
LastUpdated
Renders <p class="sarde-last-updated"> containing a <time> element with the absolute date from .Page.Updated, gated by show_updated in frontmatter (default true).
Called from the docs, labs, blog single, and default single layouts, inside the shared page meta row below the article. It renders nothing when the page has no resolvable timestamp.
The date is rendered at build time, so it is present without JavaScript and the page does not shift on load.
The display format comes from theme.date_format, which accepts short, long, iso, or any Go layout string. The short and long presets are locale-aware: each page renders the date in its own language (CLDR data for about 30 common languages, English fallback otherwise), while custom Go layouts always render English. The datetime attribute is always ISO 8601 regardless, so the markup stays machine-readable. The timestamp itself is resolved by build.last_updated.
Page meta row
The docs, labs, default single, and blog single layouts wrap EditLink and LastUpdated in a shared <div class="sarde-page-meta"> that sits between the article and the prev/next navigation:
<div class="sarde-page-meta"> {{ component "EditLink" . }} {{ component "LastUpdated" . }}</div>The row is a flex container with justify-content: space-between, so the edit link sits at the start and the last-updated line at the end, both in muted text at the small type size. On narrow viewports the row wraps to two lines. When only LastUpdated renders it still sits at the end, and when neither component renders the row collapses to display: none so no vertical gap is left behind.
The wrapper lives in the layouts rather than in a component of its own, because components are parsed before the component registry exists and therefore cannot call other components.
ContentPanel and TagSidebar
These two components are registered and overridable but not called by the default docs or default layouts. They serve as insertion points for custom layouts:
- ContentPanel wraps
.Page.Contentin a<div>. Use it to add a content-area wrapper (ads, feedback widget) without overriding the entire layout. - TagSidebar renders the top 20 tags via
topTerms "tags" 20as a sidebar widget. Used by blog list templates (_blog/list.html,_blog/list-grid.html) but not by the docs layout.