zfb
GitHub repository

Type to search...

to open search from anywhere

Transclusion

Inline the content of another file using the :::include directive.

The transclude feature lets you inline content from other files using the :::include directive. The referenced file is parsed as Markdown and its AST is merged into the including document before all other processing runs.

Enable

// zfb.config.ts
export default defineConfig({
  markdown: {
    features: {
      transclude: {},
    },
  },
});

Optional config:

transclude: {
  maxDepth: 5, // maximum include chain depth (default 5)
},

Basic usage

Use :::include with a file attribute pointing to the file you want to inline. The path is resolved relative to the current source file.

# My Document

:::include{file="./snippets/intro.md"}

More content follows.

The included file is inserted in place of the directive, so its headings, paragraphs, code blocks, and other elements appear directly in the output.

Including source code

Set code=true to treat the file contents as a code block instead of parsed Markdown. The lang attribute sets the syntax-highlighting language.

:::include{file="./examples/hello.rs" code=true lang="rust"}

Line ranges

The lines attribute slices the file to the specified lines before including. Use with code=true to show a specific excerpt from a source file.

:::include{file="./src/lib.rs" code=true lang="rust" lines="10-30"}

Line numbers are 1-based and both endpoints are inclusive.

Chaining

Included files can themselves contain :::include directives. The default maxDepth of 5 allows chains up to five levels deep. Deeper chains are rejected with an error diagnostic.

Cycle detection

If file A includes file B and file B includes file A (directly or transitively), the build emits an Error diagnostic and skips the offending directive rather than looping indefinitely.

Path restrictions

  • Relative paths only — absolute paths are rejected with an error diagnostic.

  • Project-root confinement — the resolved path must remain inside the project root. Path traversal (e.g. ../../outside) is rejected.

Blank-line requirement

The :::include fence line must be separated from surrounding content by blank lines so the Markdown parser treats it as a block directive, not inline content.

GFM constructs in included files

An included file is parsed with the host project's markdown.gfm configuration — the same construct set the including page itself uses. Tables, strikethrough, task lists, footnotes, and autolink literals therefore behave identically whether the markup is written inline or lives in an included file.

<!-- snippet.md -->
| a | b |
| - | - |
| 1 | 2 |

With markdown.gfm.table on, this renders as a table when transcluded, exactly as it would if the same three lines were pasted into the page.

Before zfb #2390 included files were always parsed with every GFM construct off, regardless of configuration, so the snippet above rendered as literal text while the identical markup in the page rendered as a table. If you have content that relied on that, turn the relevant markdown.gfm.* flag off.

Math ($$…$$ and $…$) follows the same rule as of zfb #2397: an included file is parsed with whatever the page around it is being compiled for. On the MDX/JSX path math parses, so a formula in an included file renders exactly as it would inline. On the HTML path math stays off — there, as at the top level, $$…$$ is literal text.

Before #2397 math was off on both paths. On the MDX/JSX path that was not cosmetic: the LaTeX leaked out as bare {…} expression containers, which the bundler rejects, falling the whole page back to its raw-content placeholder. Math in included files is now safe to use.

See GFM for the full construct list and its defaults.

Revision History

CreatedUpdated