Page Anatomy

Point at any region of a finished site and this page names the component that owns it. Every part below ships — the most expensive mistake a new Espalier project makes is rebuilding one of them from divs. If you are about to write a header, a footer, a light/dark toggle, or a reading-width container: stop, it exists.

The map

┌─ <esp-root> ──────────────────────────────── (invisible: theme + tokens) ─┐
│ ┌─ <esp-page> ─────────────────────────────────── (the layout shell) ───┐ │
│ │ ┌─ slot="header" → <esp-header> ────────────────────────────────────┐ │ │
│ │ │  topbar (optional row)                                            │ │ │
│ │ │  brand │ slot="menu" → <esp-menu mode="horizontal">  │ buttons ●○ │ │ │
│ │ └───────────────────────────────────────────────────────────────────┘ │ │
│ │ ┌─────────────┬─ main (default slot) ─────────────┬─────────────────┐ │ │
│ │ │             │  the content well                 │                 │ │ │
│ │ │ slot=       │  ┌─ <esp-section context="…"> ─┐  │  slot="right"   │ │ │
│ │ │ "sidebar"   │  │  a color band + its well    │  │  (right rail)   │ │ │
│ │ │             │  └─────────────────────────────┘  │                 │ │ │
│ │ │             │  <esp-stack>/<esp-row> flow,      │                 │ │ │
│ │ │             │  <esp-box> cards, <esp-form> …    │                 │ │ │
│ │ └─────────────┴───────────────────────────────────┴─────────────────┘ │ │
│ │ ┌─ slot="footer" → <esp-footer> ────────────────────────────────────┐ │ │
│ │ │  media / brand │ link-group │ link-group │ link-group │ aside     │ │ │
│ │ │  bottom (legal line)                                              │ │ │
│ │ └───────────────────────────────────────────────────────────────────┘ │ │
│ └───────────────────────────────────────────────────────────────────────┘ │
└───────────────────────────────────────────────────────────────────────────┘

Region by region

You are pointing at… Component Import
Nothing visible — the theme, tokens, scheme esp-root @taprootio/espalier/root
The whole layout: header/main/footer grid, content cap, gutters esp-page @taprootio/espalier/page
The bar across the top: brand, nav, buttons, light/dark toggle esp-header @taprootio/espalier/header
The site name / logo in that bar esp-header's brand-text / brand-logo attributes (per-scheme variants included)
The horizontal navigation esp-menu mode="horizontal" in the header's menu slot @taprootio/espalier/menu
Icon buttons at the bar's end esp-header-button in the buttons slot @taprootio/espalier/header
The light/dark toggle Built into esp-header — set theme-toggle="visible"
The hamburger + slide-out drawer on small screens esp-header show-burger with drawer-target pointing at a drawer-capable esp-menu (the target must implement openDrawer()/closeDrawer()) @taprootio/espalier/menu
The centered column your content lives in esp-page's default slot — the content well, capped by kind (wide 1536px, narrow 768px, full uncapped, site full-width section stacks)
A full-width marketing page of stacked bands esp-page kind="site" — the main region spans the viewport; sections center their own wells on --esp-page-well-max-width. The sidebar/right rails are unsupported here (they would split the shared column); use kind="wide" for railed layouts
A comfortable reading column esp-page kind="narrow" — constrains slotted children to a 66ch measure
A left navigation column esp-page's sidebar slot
A right rail esp-page's right slot
A full-width color band (a "zone") esp-section — paints the local canvas edge to edge, centers its well, and hosts a context with nothing to neutralize @taprootio/espalier/section
A column of content with themed gaps esp-stack — fields fill the column, buttons keep their natural width @taprootio/espalier/stack
A wrapping row: buttons, badges, icon-label pairs esp-row @taprootio/espalier/row
A card / panel with its own raised surface esp-box — this is what it is for @taprootio/espalier/box
The columned link area at the bottom esp-footer with esp-footer-link-group children (and esp-footer-column to pin groups together) @taprootio/espalier/footer
The legal line under the columns esp-footer's bottom slot

The parts people rebuild, and why they shouldn't

The header is not a styled div. esp-header carries the brand (text or logo, with per-scheme light-brand-logo / dark-brand-logo variants), the menu and buttons slots, scroll behaviors (compact, elevate, transparent, reveal, dock, and more), the mobile burger + drawer wiring, and the built-in scheme toggle. The toggle flips the nearest esp-root and emits esp-header-theme-toggle only for a real visitor activation, so persisting the choice is one listener:

document.querySelector("esp-root").addEventListener("esp-header-theme-toggle", (event) => {
  localStorage.setItem("scheme", event.detail.scheme);
});

The footer is not a grid you write. esp-footer columns="3" lays out slotted esp-footer-link-group elements (plain <a> children — each group is a labelled navigation landmark), with media, brand, aside, and bottom slots around them.

Alignment is a contract, not a coincidence. Slot esp-header and esp-footer directly into esp-page's named slots and the page hands them its resolved content cap and alignment as custom properties (--esp-header-content-max-width and friends) — the bar backgrounds stay full-bleed while their content aligns with the well. A wrapper element between page and header/footer breaks that handshake.

The measure container ships. esp-page kind="narrow" caps the well at 768px and constrains slotted children to a 66ch reading measure. For one narrow passage inside a wide page, prefer a nested element with max-inline-size: 66ch over rebuilding the page shell.

Bands are sections

A full-width color band is a theme zone: a context applied to a container, which re-derives and re-enforces the full token table for that subtree. The host is esp-section: it paints the local canvas edge to edge, centers its content in a well, and carries no card identity — no raised surface, padding, or shadow to neutralize:

<esp-section context="inverted">
  <h2>A reversed band</h2>
  <p>Everything in here — including plain light-DOM content — renders on
  the zone's tokens.</p>
</esp-section>

A band can also paint one decorative raster mask behind its well. Set --esp-section-decoration-image plus optional color, position, size, and opacity hooks; esp-section clips the plane, prevents repetition and pointer capture, and keeps content above it. The default tint is the context-local heading color, so one alpha asset can follow normal and inverted zones. Treat the image value as trusted stylesheet input and validate any externally supplied URL before assigning it.

Inside esp-page kind="site" sections run edge to edge and share one content column with the header and footer (--esp-page-well-max-width); inside the capped kinds a band spans the content well. (Before esp-section shipped, the recipe was a neutralized esp-box — replace those with a bare section.) Keep a reversed band's canvas out of the mid band — a canvas near L 0.45 sits exactly where the zone's own filled buttons are placed, and swallows them. The mechanism and the fix are in the theming guide.

Where to go next

  • Build a Site — the end-to-end path from brand book to themed page using every part named here.
  • Theming — anchors, roles, contexts.
  • The Lightness Ramp — seating brand swatches on the ramp.
Components API Guides Getting started Styling Espalier Browser support GitHub npm package Taproot I/O