Documentation Shell Partials

Every documentation page on a Leed site is assembled by about thirty partials under leed/docs/. None of them are yours to call. They are documented for two reasons: because an ejected header or footer has to live inside them and cooperate with what surrounds it, and because an id in a stack trace or a devtools inspector should be legible rather than mysterious.

Which of the three layouts a set uses is a CMS choice, described with screenshots at Documentation Layouts. The one override with a real contract is Customizing the Documentation Header and Footer — this page is the substrate that page assumes.

A documentation page at desktop width with each region outlined and labeled: the fixed header band across the top, the left sidebar with its filter box, the breadcrumbs and page title, the content column, the table of contents on the right, and the previous/next links at the foot of the column.
The six regions and their ids: #docs-header-wrapper, #docs-sidebar-nav (containing #docs-nav-filter), #leed-docs-copy, #docs-content, #docs-toc-wrapper, and #docs-pagination.

The call tree

Four levels, top to bottom. leed-documentation.hbs — the one layout every documentation and API page type is bound to — resolves {{> (docsLayoutTemplate) }} to leed/docs/<layoutName>/base. That theme’s base.hbs opens the shell as a block partial and supplies its own containers as the body, branching on {{#if openapi.endpoint}} between the theme’s documentation and api variants. From there the shared partials do the work.

flowchart TD
  L["_layouts/leed-documentation.hbs"] --> B["leed/docs/&lt;theme&gt;/base"]
  B --> S["leed/docs/shell"]
  S --> H["leed/head"]
  S --> HV["header partial<br/>top-search | compact"]
  S --> PB["@partial-block"]
  S --> MOD["leed/docs/document-search-modal"]
  HV --> CH["leed/docs/header/chrome"]
  CH --> OV["docs-header.hbs<br/>(your override)"]
  CH --> DEF["scroll indicator +<br/>#docs-header-container"]
  DEF --> BR["header/brand"]
  DEF --> NAV["header/nav"]
  DEF --> CTA["header/cta"]
  DEF --> DS["leed/docs/document-search"]
  NAV --> MB1["leed/menu/builder (top)"]
  PB --> V["&lt;theme&gt;/documentation | &lt;theme&gt;/api"]
  V --> SB["leed/docs/sidebar"]
  V --> MINI["leed/docs/mini-bar"]
  V --> ART["leed/docs/doc-article | api-article"]
  V --> TOC["leed/docs/toc"]
  SB --> MB2["leed/menu/builder (left)"]
  ART --> API["leed/api/** (12 partials)"]
  ART --> PG["leed/docs/pagination"]
  PG --> FT["leed/docs/footer"]
  FT --> DF["leed/docs/docs-footer"]
  FT --> OF["docs-footer.hbs<br/>(your override)"]

leed/docs/shell

The shell owns the whole document: <!DOCTYPE>, the <html> element, <head> (which is where leed/head is called), and <body>. The <html> class list is scroll-smooth js-focus-visible leed-documentation plus whatever {{ leedConfiguredCSS }} composes from the page type’s font, layout name, color theme and code theme — that is the hook every documentation stylesheet scopes to. See Themes, Fonts and Code Themes.

{{#> leed/docs/shell header="leed/docs/header/top-search" topGrow=true siteFooter=true }}
...your containers...
{{/leed/docs/shell}}
ParameterEffect
headerthe name of a partial, resolved with {{> (lookup . "header") }}
topGrowput grow on the header-scope wrapper
bodyGrowput grow on the body content wrapper
siteFooterrender the docs footer at body level, outside the header scope

Everything between the header and the closing tag sits inside one Alpine scope, documentationHeaderComponent({scrollBarId: 'documentation'}), and the body wrapper carries mt-(--height-header) — the page’s top margin is a runtime measurement, not a constant, because the header’s height depends on the layout and the viewport. At the end of that scope, and once per page, the shell renders leed/docs/document-search-modal, so every search trigger anywhere on the page opens the same modal.

:::warning {{> @partial-block }} must start at column 0 Handlebars indents a partial’s entire output by the indentation of its call site. Indent the block-body call and every rendered <pre><code> block on the page is indented with it, which breaks code display. The shipped shell and all three theme bases call it flush left for exactly this reason — keep that if you write a master template of your own, as described at Layouts and Page Types. :::

The header chrome

leed/docs/header/chrome is itself a block partial. It renders #docs-header-wrapper — the element each theme positions and documentation.js measures — and an x-effect that publishes --height-header and --height-toc onto the document element. Inside the wrapper is the override branch:

{{#if (and (useCustomTemplate "docsHeader") (hasTier "starter")) }}
    {{> docs-header }}
{{else}}
    {{> leed/components/scroll-status-indicator-horizontal }}

    <header id="docs-header-container" class="text-(--site-text-color) ">
        {{> @partial-block }}
    </header>
{{/if}}

The scroll indicator is invoked here with no scrollBarId, and that partial renders nothing without one — so no documentation page currently shows a reading-progress bar, on any of the three layouts.

top-search and compact

Two header variants fill the wrapper, and the theme chooses between them by passing a name to the shell. top-search puts the logo, a centered search control and the CTA on one row with the navigation on its own row underneath; alpha and charlie use it. compact puts the logo on the left and groups navigation, search and CTA to the right of it on a single row; bravo uses it. Both are block-partial calls into chrome, so both get the same wrapper and the same override branch.

brand, nav and cta

PartialRendersNotes
header/brand#docs-menu-logo — the mobile menu toggle and the logo linkthe toggle flips topMenuOpen; the logo is a div.nav-logo painted from --nav-logo-url
header/nav#docs-navigation-button-wrapper wrapping nav#menu-navtakes openClass, the theme’s styling for the open mobile dropdown; calls {{> leed/menu/builder menuName=(docsMenuName "top") }}
header/ctadiv.docs-header-right-ctatakes wrapperClass; renders one <a class="docs-button-primary"> only when documentationConfiguration.header.button exists

The sidebar

leed/docs/sidebar is #docs-sidebar-nav with x-data="sidebarNav()", containing #docs-navigation with x-data="leedDocsNavigation", which contains the filter box and then {{> leed/menu/builder menuName=(docsMenuName "left") }}. Those are the ids to target in CSS; the left menu itself is the same menu that decides your URLs, described at Left Navigation Menu.

Two details in the structure look odd until you know why they are there:

  • #docs-nav-filter is server-rendered in full and carries no x- attributes. Nothing injects it, and Alpine never adopts it, so the filter stays out of the reactivity graph and typing in it does not re-evaluate the nav. It sits inside #docs-navigation because below lg that element is the fixed drawer panel — a sibling would render behind the overlay.
  • #docs-nav-filter-empty, the “No matching pages” message, sits outside #docs-nav-filter. A site that hides the filter with #docs-nav-filter { display: none } therefore keeps the empty state, and the message reads where the list was rather than up in the header.

The sidebar also closes only on a real breakpoint crossing, not on every resize — a blanket close fired when a mobile soft keyboard opened, which shut the drawer the instant a reader tapped the filter.

The mini bar

#docs-mini-bar exists below the lg breakpoint only. It always carries #sidebar-toggle-button, which toggles $store.sidebar.open. What sits beside it depends on the page: a documentation page gets a Jump to button opening #docs-mini-toc, and an API page — which has no table of contents — gets breadcrumbs instead, rendered by {{{ breadcrumbsNav '<i class="home"></i>' }}} with an optional breadcrumbClass.

The mobile table of contents is not a second copy. documentation.js moves the single desktop .leed-nav-toc node into #leed-mobile-toc-container below lg and moves it back above. Any CSS you write for the rail should be scoped under #leed-toc so it does not follow the node into the dropdown.

The same documentation page at mobile width: the compact mini bar with a sidebar toggle and a "Jump to" button, the sidebar collapsed out of view, and the table-of-contents dropdown open over the content.

The table of contents

leed/docs/toc is seven lines — #docs-toc-wrapper wrapping aside#leed-toc, a heading, and one call:

{{{ toc content '{"tags": ["h2", "h3"], "wrapper": "div", "wrapperClass": "leed-nav-toc"}' }}}

toc comes from eleventy-plugin-toc; it is not a Leed helper, and it reads the rendered content rather than the source. The ids it links to are produced by markdown-it-anchor, which is configured for heading levels 1 through 5 and slugifies with the same slugifier the rest of the build uses. A sixth-level heading gets no anchor, so it can never appear in the table of contents — which is one more reason a documentation body stays within ## and ###.

The article

leed/docs/doc-article is the body of a documentation page: breadcrumbs, then <section id="leed-docs-copy"> holding <h1>{{{ title }}}</h1>, then <article> wrapping <section id="{{ default contentId "docs-content" }}">{{{ process content }}}</section>, then leed/docs/pagination.

#leed-docs-copy is worth remembering: it wraps the H1 and the prose and nothing else. Breadcrumbs, pager, table of contents, sidebar, header and footer are all outside it, which is why the docs theme’s body-link color is scoped to it. Its parameters are contentId (bravo passes content, because its own layout container already uses docs-content), prevLabel, nextLabel and footer.

leed/docs/api-article is the API equivalent: a two-column endpoint page whose main column is built from the twelve leed/api/** partials — title, method badge, path, security, four kinds of parameter, request body and responses — and whose side column holds the page’s own {{{ content }}}, which is where the generated code samples live. The feature those partials serve is described at API Reference Pages.

The twelve leed/api/** partials
PartialParametersCalled from
leed/api/securitysecurityapi-article
leed/api/security-constraintsschemesecurity
leed/api/parametersparameters, paramTypeapi-article, once each for path, query, header and cookie
leed/api/propertyname, schema, required, description, exampleparameters, object
leed/api/objectschema, skipHeaderproperty, request-body, responses
leed/api/request-bodyrequestBodyapi-article
leed/api/responsesresponsesapi-article
leed/api/bits/array-typeitems, isUnion, withSpansobject, property
leed/api/bits/badgesrequired, nullableproperty, object
leed/api/bits/descriptiondescriptionproperty, object
leed/api/bits/examplesexample, schema, isNestedproperty, object
leed/api/bits/scopesscopes, typesecurity, property

leed/docs/pagination renders nav#docs-pagination containing {{{ previousPageNav }}} and {{{ nextPageNav }}}, and — when a theme passes footer=true — the docs footer inline underneath, with hideLogo=true.

leed/docs/footer is only two things: the wrapper #docs-footer-wrapper and the Starter-gated override branch. leed/docs/docs-footer is what actually renders — the bottom menu via docsMenuName "bottom", the social icons row, and the copyright line whose {{else}} branch is the “Powered by Leed” badge. That gate, and what you can and cannot change about it, is the subject of Customizing the Documentation Header and Footer.

The three layout themes

Each theme’s base.hbs differs only in what it passes to the shell and how it shapes its containers; every one of them then uses the same sidebar, mini bar, article and TOC.

Themeshell parametersContainer shapeWhere the footer sitsHeader variant
alphaheader="leed/docs/header/top-search"#docs-container capped at max-w-[1408px], three columnsinside the content column (doc-article footer=true)top-search
bravoheader="leed/docs/header/compact", bodyGrow=truefull width, fixed background panel behind a centered #docs-contentat the bottom of #docs-content-wrappercompact
charlieheader="leed/docs/header/top-search", topGrow=true, siteFooter=truefull width; content and TOC centered together at max-w-5xlat body level, below the header scopetop-search

Bravo is also the theme that passes contentId="content" to the article, and the only one that labels its pager links Previous and Next on documentation pages alongside charlie; alpha leaves them unlabeled.

Alpine components on a documentation page

Your override markup can read the state these expose without declaring its own x-data.

ComponentBound toState it exposes
documentationHeaderComponentthe shell’s header scope wrapperheaderSearchShow, topMenuOpen, isSmallerThanDesktop, isSmallest, headerHeight, tocHeight, hasScrollBar
sidebarNav#docs-sidebar-navopen, isSmallerThanDesktop; methods toggle(), close(), handleResize()
leedDocsNavigation#docs-navigationthe nav menu manager
scrollStatusIndicatorHorizontalHandler(id)the scroll indicatorpercent
responseSelector, requestBodySelector, securitySelectorthe API dropdownsstatus, content-type and scheme selection

There is also one Alpine store, $store.sidebar, with a single open boolean — that is what the mini bar’s toggle writes and what sidebarNav watches.

Two partials you may use

leed/docs/document-search renders the visible search trigger. Pass compact=true for the icon-only variant, whose style hook is #document-search-container.search-compact. The trigger sets headerSearchShow, which is state owned by the docs shell, and the shell is what renders the modal it opens — so it works inside the documentation layout and nowhere else. On a marketing page there is no such scope and no search index, and the button would render and do nothing.

leed/docs/social-icons reads the company’s externalAccounts and renders one <a class="social-icon <network>-colors"> per configured account: LinkedIn, Discord, Bluesky, X, Facebook, Mastodon, Instagram, TikTok, Twitch, Reddit, GitHub and GitLab. It reads nothing from documentationConfiguration, which is why it appears on a documentation footer even when the footer’s menu slot is unset.

Styling any of these ids means writing CSS that wins against Leed’s own without reaching for !important — the layering rules are at Cascade Layers and Overriding Leed, and the reader-facing behavior of this chrome, from breadcrumbs to dark mode, is at Documentation Reading Experience.

ESC