Skip to content
Documentation contents

Composition pages

Name a source page with .compose before its extension to keep it available as composition content without automatically publishing its page-owned output. For example, src/introduction/page.compose.md can contain:

---
title: Shared introduction
---

Content to render inside another page or collect through global data.

Filenames and metadata

Composition filenames follow the normal page file conventions:

Page kind Composition filename
Directory Markdown page page.compose.md or README.compose.md
Directory HTML page page.compose.html
Directory JavaScript or TypeScript page page.compose.js or page.compose.ts
Loose Markdown page chapter.compose.md

The .compose marker applies to supported page extensions, not just Markdown. PageInfo.compose is a boolean determined once at discovery: true for composition pages and false for ordinary standalone pages. Global, layout, companion, and builder variables cannot override this classification, and it is not inherited from a directory or layout. compose is not a special page variable; vars.compose is ordinary user data and does not control output. There is no CLI toggle for composition.

Automatic output

Composition pages suppress all automatic page-owned output: the primary HTML file, all page and layout pageOutputs hooks, and the page’s workers.json file. Static asset copying and bundle generation are unchanged, including colocated styles, client bundles, and worker bundles. Their URLs and output paths remain metadata, not a guarantee that files are published.

Drafts

Draft inclusion and composition are independent. For a composition draft, the only combined suffix order is .compose.draft.ext, such as page.compose.draft.md, README.compose.draft.md, or chapter.compose.draft.md. Do not use .draft.compose.ext.

Source filename Default build With --drafts
page.md Available; automatic page-owned output Available; automatic page-owned output
page.draft.md Ignored Available; automatic page-owned output
page.compose.md Available for composition; no automatic page-owned output Available for composition; no automatic page-owned output
page.compose.draft.md Ignored Available for composition; no automatic page-owned output

Enabling drafts does not turn a composition page into a standalone page.

Global data and explicit rendering

Source-backed composition pages remain available to global.data.ts, unless excluded as drafts. They support explicit calls to renderInnerPage() or renderFullPage(), subject to the normal data-subscription rules. Explicit rendering returns content without publishing the page or running its pageOutputs hooks. Use page.pageInfo.compose to select fragments or standalone pages:

// Inside global.data.ts.
const fragments = pages.filter(page => page.pageInfo.compose === true)
const standalonePages = pages.filter(page => page.pageInfo.compose === false)

Do not assume a page’s URL means that it is published.

Generated pages

Generated page definitions use the optional top-level boolean compose, parallel to draft, defaulting to false:

// src/introduction.pages.ts
export default {
  outputName: 'introduction/index.html',
  compose: true,
  draft: false,
  vars: { title: 'Shared introduction' },
  children: '<p>Shared content</p>',
}

The definition’s compose field sets PageInfo.compose; vars.compose does not control output. compose: true suppresses automatic page-owned output without changing bundle generation or static asset copying. Generated pages remain downstream of global data and are not added to its source-backed PageData[] collection, regardless of compose. Their URLs and output paths remain metadata even when no page file is published.

Documentation