Skip to main content
Sarde
On this page

UI Components

Reference for named template components that render layout chrome, and how their three-layer overlay resolves

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).

HTML
{{ 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:

HTML
{{ 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:

Text
Head
Header
├── SiteTitle
├── GlobalNav
├── Search
├── VersionSwitcher
├── LanguageSwitcher
├── Social (if header.social enabled)
├── CenterToggle
└── ThemeToggle
MobileTableOfContents (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)
DraftBanner
FallbackNotice
VersionBanner
PageBanner
PageTitle
PageTags
[page content]
Pagination (if pagination exists)
Footer
└── Social
Scripts

The 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

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.

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.

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.

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).

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.

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:

HTML
<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.Content in 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" 20 as a sidebar widget. Used by blog list templates (_blog/list.html, _blog/list-grid.html) but not by the docs layout.
Edit this page

Last updated: