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.
#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/<theme>/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["<theme>/documentation | <theme>/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}}| Parameter | Effect |
|---|---|
header | the name of a partial, resolved with {{> (lookup . "header") }} |
topGrow | put grow on the header-scope wrapper |
bodyGrow | put grow on the body content wrapper |
siteFooter | render 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
| Partial | Renders | Notes |
|---|---|---|
header/brand | #docs-menu-logo — the mobile menu toggle and the logo link | the toggle flips topMenuOpen; the logo is a div.nav-logo painted from --nav-logo-url |
header/nav | #docs-navigation-button-wrapper wrapping nav#menu-nav | takes openClass, the theme’s styling for the open mobile dropdown; calls {{> leed/menu/builder menuName=(docsMenuName "top") }} |
header/cta | div.docs-header-right-cta | takes 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-filteris server-rendered in full and carries nox-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-navigationbecause belowlgthat 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 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
| Partial | Parameters | Called from |
|---|---|---|
leed/api/security | security | api-article |
leed/api/security-constraints | scheme | security |
leed/api/parameters | parameters, paramType | api-article, once each for path, query, header and cookie |
leed/api/property | name, schema, required, description, example | parameters, object |
leed/api/object | schema, skipHeader | property, request-body, responses |
leed/api/request-body | requestBody | api-article |
leed/api/responses | responses | api-article |
leed/api/bits/array-type | items, isUnion, withSpans | object, property |
leed/api/bits/badges | required, nullable | property, object |
leed/api/bits/description | description | property, object |
leed/api/bits/examples | example, schema, isNested | property, object |
leed/api/bits/scopes | scopes, type | security, property |
Pagination and footer
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.
| Theme | shell parameters | Container shape | Where the footer sits | Header variant |
|---|---|---|---|---|
| alpha | header="leed/docs/header/top-search" | #docs-container capped at max-w-[1408px], three columns | inside the content column (doc-article footer=true) | top-search |
| bravo | header="leed/docs/header/compact", bodyGrow=true | full width, fixed background panel behind a centered #docs-content | at the bottom of #docs-content-wrapper | compact |
| charlie | header="leed/docs/header/top-search", topGrow=true, siteFooter=true | full width; content and TOC centered together at max-w-5xl | at body level, below the header scope | top-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.
| Component | Bound to | State it exposes |
|---|---|---|
documentationHeaderComponent | the shell’s header scope wrapper | headerSearchShow, topMenuOpen, isSmallerThanDesktop, isSmallest, headerHeight, tocHeight, hasScrollBar |
sidebarNav | #docs-sidebar-nav | open, isSmallerThanDesktop; methods toggle(), close(), handleResize() |
leedDocsNavigation | #docs-navigation | the nav menu manager |
scrollStatusIndicatorHorizontalHandler(id) | the scroll indicator | percent |
responseSelector, requestBodySelector, securitySelector | the API dropdowns | status, 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.