Overview
quartz.layout.ts controls where components appear on every page. It exports a PageLayout object that maps eight named slots to arrays of Quartz components. Components within a slot render in order; empty arrays remove the slot entirely. Per-page-type overrides let content pages, folder pages, and tag pages differ without a custom template.
Understand the eight slots before touching the file
The slot names map directly to HTML regions in the default template.
| Slot | Location |
|---|---|
head | Inside <head>: meta tags, styles, scripts |
header | Top bar visible on all pages |
beforeBody | Between the header and the main content column |
left | Left sidebar |
right | Right sidebar |
pageBody | Main content area (usually Component.Content() alone) |
afterBody | Below the main content, above the footer |
footer | Bottom of every page |
Do not move Component.Content() out of pageBody. Every other component is optional. See quartz-components for the built-in component catalog.
Assign sharedLayout for elements that appear on every page
sharedLayout applies to all page types unless overridden. Put navigation, search, and the footer here.
export const sharedLayout: SharedLayout = {
head: Component.Head(),
header: [Component.PageTitle(), Component.Search(), Component.Darkmode()],
afterBody: [],
footer: Component.Footer({ links: { GitHub: "https://github.com/…" } }),
}Component.Head() must be the sole element in head; it owns <title>, canonical tags, and Open Graph metadata. Adding a second head component breaks deduplication.
Use defaultContentPageLayout for article pages
defaultContentPageLayout controls the most common page type: a single markdown file rendered as an article.
export const defaultContentPageLayout: PageLayout = {
beforeBody: [
Component.Breadcrumbs(),
Component.ArticleTitle(),
Component.ContentMeta(),
Component.TagList(),
],
left: [
Component.PageTitle(),
Component.MobileOnly(Component.Spacer()),
Component.Search(),
Component.Darkmode(),
Component.Explorer(),
],
right: [
Component.Graph(),
Component.DesktopOnly(Component.TableOfContents()),
Component.Backlinks(),
],
}TableOfContents belongs in the right sidebar on desktop; wrapping it in Component.DesktopOnly() hides it on narrow viewports where it would overlap content.
Use defaultListPageLayout for index pages
Folder pages and tag pages use defaultListPageLayout. They rarely need a table of contents or backlinks, so the right sidebar is simpler.
export const defaultListPageLayout: PageLayout = {
beforeBody: [Component.Breadcrumbs(), Component.ArticleTitle(), Component.ContentMeta()],
left: [
Component.PageTitle(),
Component.MobileOnly(Component.Spacer()),
Component.Search(),
Component.Darkmode(),
Component.Explorer(),
],
right: [],
}Leaving right as an empty array collapses the right column. Quartz uses a CSS grid that reflows to two columns when the right array is empty, giving list pages a wider body.
Wrap responsive components with MobileOnly and DesktopOnly
Quartz ships two helper components that toggle visibility via CSS class injection.
Component.MobileOnly(Component.Spacer()) // renders only on viewports < 768 px
Component.DesktopOnly(Component.TableOfContents()) // hidden on mobileThese are thin wrappers, not media-query logic in the component itself. The child component still mounts; the CSS class controls visibility. Avoid wrapping expensive components in MobileOnly expecting a performance benefit; the work still runs server-side.
Use ConditionalRender to show a component only on specific slugs
ConditionalRender takes a component and a predicate function that receives the current page’s FileData. Use it when a component belongs on some content pages but not others.
Component.ConditionalRender({
component: Component.Graph(),
condition: (page) => !page.slug?.startsWith("cheatsheets/"),
})The predicate runs at build time per page, so there is no runtime cost. Use it sparingly; if more than three conditionals accumulate, consider a dedicated page type instead. See quartz-components for writing custom components that implement the same logic internally.
Keep layout changes in sync with the theme
The layout file consumes the font and color values from quartz.config.ts. Changing theme.colors takes effect globally without touching the layout. Custom per-slot styles go in component .css properties, not as inline overrides in the layout file. See quartz-config for the theme object shape.