Summary
Nue currently supports:
- full page Markdown rendering through Nuemark (
.md pages)
- inline Markdown string rendering through the
markdown(...) helper in HTML templates
What is missing is a content-first way to include a reusable Markdown snippet inside either:
- an HTML layout/template
- another Nuemark document
This issue proposes a Markdown Partial feature using a shared tag name in both renderers:
<markdown src="./partials/intro.md" />
[markdown src=./partials/intro.md]
The goal is to make reusable Markdown snippets first-class server-rendered partials, without trying to make .md files behave like full HTML-based Nue components.
Why This Feature
This feature is motivated by a practical authoring gap.
Today, if content needs a heading or richer block structure inside YAML or inside reused snippets, the available options are limited:
- keep the content inline in HTML
- pass strings through
markdown(...)
- use raw HTML in data files
- promote the content into a full page-level
.md file
Those options work, but they are awkward for reusable content blocks that are still fundamentally Markdown/content rather than UI runtime components.
A Markdown Partial feature would let users keep content in Markdown files and include it where needed without forcing that content into either:
- YAML multiline edge cases
- raw HTML fragments
- HTML component libraries
Preferred API
Use the tag name markdown in both HTML and Nuemark.
In HTML templates/layouts
<markdown src="./partials/intro.md" />
<markdown src="./partials/callout.md" title="Fast path" tone="note" />
In Nuemark content
[markdown src=./partials/intro.md]
[markdown]
src: ./partials/callout.md
title: Fast path
tone: note
This mirrors existing paired concepts like <svg> and [svg], keeps the API short, and fits Nue's existing tag-oriented mental model.
Proposed Behavior
Core semantics
markdown renders a referenced .md file as a server-rendered partial.
- It is not a new full Nue component type.
- It does not become a client-mounted/hydrated component.
- It returns rendered HTML at build/render time.
- It should work both in HTML templates and in Nuemark documents.
File type scope
For v1, only .md targets should be supported.
If broader include semantics are wanted later, they should be handled as a separate feature rather than folded into the first implementation.
Path resolution
- Relative
src values resolve relative to the file containing the markdown tag.
- Absolute-like paths such as
/docs/intro.md resolve from site root.
- Nested partials resolve relative to the partial file that contains the nested include.
- Escaping outside the site root should be rejected.
Data model
The most useful precedence order appears to be:
- outer page/template data
- partial front matter
- include-site overrides from tag attributes or YAML tag body
That gives partial files sane defaults while keeping include sites explicit and overridable.
Example:
<markdown src="./partials/callout.md" tone="warning" />
If callout.md contains front matter like:
---
tone: note
title: Heads up
---
then inside the partial:
title resolves to Heads up
tone resolves to warning
- all ordinary outer page/template data is still available as base context
Metadata behavior
Partial front matter should be local to the partial render only.
It should not modify outer page-level values such as:
- page
title
- page
description
- outer
url
- outer
slug
- outer parsed
headings
- page-level metadata used by layouts, collections, feed generation, etc.
In other words, the partial render gets a local merged context, but the outer page remains authoritative for page/document metadata.
Nested partials
Nested partials should be supported.
This is important because once the feature exists, users will naturally want to compose reusable callouts, intros, footnotes, etc.
Cycle handling
Cycles should fail clearly and early, for example:
a.md includes b.md
b.md includes a.md
The error should report the include chain so users can fix it quickly.
Why This Should Be a Markdown Partial, Not a Full Nue Component
This feature solves a similar authoring need as HTML components, but it should not try to be the same abstraction.
Current architecture distinction
HTML-based Nue components are AST-based and can participate in:
- server-side rendering
- client mounting/hydration
- HTML library discovery
- JS module generation/import for runtime mounting
Markdown does not currently participate in that model. It renders to HTML strings through Nuemark.
Trying to make .md files into full Nue components would likely require a second component model or a new compilation target.
That would add substantially more complexity than the core use case justifies.
Better framing
This feature fits better as:
- reusable content partials
- server-rendered snippets
- content composition
rather than:
- interactive/runtime components
- mountable islands
- HTML AST component libraries
Suggested Implementation Direction
This appears best implemented primarily in Nuekit, not as a new fundamental Nuemark component model.
HTML path
HTML rendering already has a built-in hook for tag-specific render functions.
That makes <markdown ... /> a good fit as a built-in render function, rather than as a new compiled HTML component type.
Nuemark path
Nuemark rendering already supports tag renderers.
That makes [markdown ...] a good fit as a built-in Nuemark tag resolved from the same page-scoped partial renderer.
Shared renderer
The cleanest implementation is likely a shared page-scoped partial rendering helper/factory that both the HTML and Nuemark render paths can call.
That helper would:
- resolve the referenced asset
- parse the referenced Markdown file
- merge local render data
- render the partial through Nuemark
- support nested partial includes
- track include ancestry for cycle detection
- register dependency edges for rebuild/HMR
Likely Implementation Surface
packages/nuekit/src/render/page.js
Primary orchestration point.
Likely responsibilities:
- inject built-in
<markdown> render function for HTML rendering
- inject built-in
[markdown] tag renderer for Nuemark rendering
- share one page-scoped partial renderer between both paths
- reuse current page data and current Nuemark tag/component context
packages/nuekit/src/asset.js
Likely responsibilities:
- resolve related assets by path
- support relative and root-based markdown partial lookup
- track explicit partial dependencies outside the normal convention-based dependency model
- maintain ancestry/include chain for cycle detection
packages/nuekit/src/site.js and/or dev server invalidation flow
Likely responsibilities:
- support invalidation/re-render of parent pages when a referenced partial changes
- ensure dev-server updates affect the correct pages
packages/nuedom/src/dom/node.js
Possibly needed.
HTML built-in render functions currently receive merged data from:
- evaluated attributes
- outer template data
If attribute precedence is wrong for this use case, this merge order may need adjustment so include-site overrides reliably win over inherited outer data.
This is worth checking carefully because the expected precedence for partial includes is that explicit include-site overrides win.
Tests
Likely test files:
packages/nuekit/test/render/md.test.js
packages/nuekit/test/render/asset-render.test.js
- possibly dev-server/HMR-focused tests if current harness supports it
Acceptance Criteria
Rendering
- An HTML page can render
<markdown src="./partial.md" />.
- A Nuemark page can render
[markdown src=./partial.md].
- Output is rendered HTML, not a client stub.
- Nested partials render correctly.
Resolution and safety
- Relative resolution works from the containing file.
- Root-based resolution works from site root.
- Non-
.md targets are rejected in v1.
- Cycles are rejected with a useful error message.
- Paths outside the site root are rejected.
Data behavior
- Outer page/template data is available inside the partial.
- Partial front matter is merged locally.
- Include-site overrides win over partial front matter and outer data.
- Partial metadata does not mutate outer page metadata.
Integration
- Partials can use the same Nuemark custom tags available to the page.
- Changes to a partial invalidate/re-render affected pages in dev mode.
- Build output is correct without requiring client-side execution.
Complexity
Estimated implementation complexity: medium-high.
Why not low
This is more than a small helper because it crosses:
- HTML rendering
- Nuemark rendering
- file resolution
- dependency tracking
- dev invalidation/HMR behavior
- partial-local data precedence
Why not extremely high
The feature still aligns with existing extension points:
- HTML built-in render functions already exist
- Nuemark tag renderers already exist
- Markdown parsing/rendering already exists
- Nuekit already owns site/file/asset context
The feature does not require inventing a second full component runtime if kept scoped to server-rendered partials.
Main Risks
1. Data precedence confusion
The most immediate behavioral risk is ambiguous precedence between:
- outer page data
- partial front matter
- explicit include-site overrides
If that order is not defined and tested carefully, users will get surprising results.
2. Dependency invalidation gaps
Nue's normal dependency system is convention-based. Markdown partials introduce explicit, file-level include edges.
If those edges are not tracked, then:
- dev updates may not refresh parent pages correctly
- incremental builds may miss affected parents
3. Cycle handling / recursive rendering
Once nested partials are allowed, cycle protection becomes mandatory.
Without explicit ancestry tracking, recursive includes can fail badly or produce opaque errors.
4. Scope creep into full component behavior
It will be tempting to extend this into:
- interactive markdown components
- slot behavior
n- mountable client islands
- generic include semantics for many file types
That should be resisted in the first implementation. The value of this feature is that it stays content-first and server-rendered.
5. Interaction with existing component/template data expectations
Depending on how HTML built-in render functions receive data, there may be overlap with the broader question of how inline HTML constructs see outer template data.
This should be handled narrowly for markdown partials rather than using the feature as implicit justification for broader component-data behavior changes.
Non-Goals for v1
- making
.md files full Nue components
- client hydration / mount support for markdown partials
- generic partial support for arbitrary file types
- slot APIs for markdown partials
- executing JS runtime behavior from markdown partials
Recommendation
Proceed with this feature as a Markdown Partial implementation with:
<markdown> in HTML
[markdown] in Nuemark
- server-rendered only
.md targets only in v1
- explicit dependency tracking
- strong tests around precedence, nesting, and invalidation
That gives users a meaningful content-composition feature without forcing Markdown into the existing HTML component runtime model.
Summary
Nue currently supports:
.mdpages)markdown(...)helper in HTML templatesWhat is missing is a content-first way to include a reusable Markdown snippet inside either:
This issue proposes a Markdown Partial feature using a shared tag name in both renderers:
The goal is to make reusable Markdown snippets first-class server-rendered partials, without trying to make
.mdfiles behave like full HTML-based Nue components.Why This Feature
This feature is motivated by a practical authoring gap.
Today, if content needs a heading or richer block structure inside YAML or inside reused snippets, the available options are limited:
markdown(...).mdfileThose options work, but they are awkward for reusable content blocks that are still fundamentally Markdown/content rather than UI runtime components.
A Markdown Partial feature would let users keep content in Markdown files and include it where needed without forcing that content into either:
Preferred API
Use the tag name
markdownin both HTML and Nuemark.In HTML templates/layouts
In Nuemark content
This mirrors existing paired concepts like
<svg>and[svg], keeps the API short, and fits Nue's existing tag-oriented mental model.Proposed Behavior
Core semantics
markdownrenders a referenced.mdfile as a server-rendered partial.File type scope
For v1, only
.mdtargets should be supported.If broader include semantics are wanted later, they should be handled as a separate feature rather than folded into the first implementation.
Path resolution
srcvalues resolve relative to the file containing themarkdowntag./docs/intro.mdresolve from site root.Data model
The most useful precedence order appears to be:
That gives partial files sane defaults while keeping include sites explicit and overridable.
Example:
If
callout.mdcontains front matter like:then inside the partial:
titleresolves toHeads uptoneresolves towarningMetadata behavior
Partial front matter should be local to the partial render only.
It should not modify outer page-level values such as:
titledescriptionurlslugheadingsIn other words, the partial render gets a local merged context, but the outer page remains authoritative for page/document metadata.
Nested partials
Nested partials should be supported.
This is important because once the feature exists, users will naturally want to compose reusable callouts, intros, footnotes, etc.
Cycle handling
Cycles should fail clearly and early, for example:
a.mdincludesb.mdb.mdincludesa.mdThe error should report the include chain so users can fix it quickly.
Why This Should Be a Markdown Partial, Not a Full Nue Component
This feature solves a similar authoring need as HTML components, but it should not try to be the same abstraction.
Current architecture distinction
HTML-based Nue components are AST-based and can participate in:
Markdown does not currently participate in that model. It renders to HTML strings through Nuemark.
Trying to make
.mdfiles into full Nue components would likely require a second component model or a new compilation target.That would add substantially more complexity than the core use case justifies.
Better framing
This feature fits better as:
rather than:
Suggested Implementation Direction
This appears best implemented primarily in Nuekit, not as a new fundamental Nuemark component model.
HTML path
HTML rendering already has a built-in hook for tag-specific render functions.
That makes
<markdown ... />a good fit as a built-in render function, rather than as a new compiled HTML component type.Nuemark path
Nuemark rendering already supports tag renderers.
That makes
[markdown ...]a good fit as a built-in Nuemark tag resolved from the same page-scoped partial renderer.Shared renderer
The cleanest implementation is likely a shared page-scoped partial rendering helper/factory that both the HTML and Nuemark render paths can call.
That helper would:
Likely Implementation Surface
packages/nuekit/src/render/page.jsPrimary orchestration point.
Likely responsibilities:
<markdown>render function for HTML rendering[markdown]tag renderer for Nuemark renderingpackages/nuekit/src/asset.jsLikely responsibilities:
packages/nuekit/src/site.jsand/or dev server invalidation flowLikely responsibilities:
packages/nuedom/src/dom/node.jsPossibly needed.
HTML built-in render functions currently receive merged data from:
If attribute precedence is wrong for this use case, this merge order may need adjustment so include-site overrides reliably win over inherited outer data.
This is worth checking carefully because the expected precedence for partial includes is that explicit include-site overrides win.
Tests
Likely test files:
packages/nuekit/test/render/md.test.jspackages/nuekit/test/render/asset-render.test.jsAcceptance Criteria
Rendering
<markdown src="./partial.md" />.[markdown src=./partial.md].Resolution and safety
.mdtargets are rejected in v1.Data behavior
Integration
Complexity
Estimated implementation complexity: medium-high.
Why not low
This is more than a small helper because it crosses:
Why not extremely high
The feature still aligns with existing extension points:
The feature does not require inventing a second full component runtime if kept scoped to server-rendered partials.
Main Risks
1. Data precedence confusion
The most immediate behavioral risk is ambiguous precedence between:
If that order is not defined and tested carefully, users will get surprising results.
2. Dependency invalidation gaps
Nue's normal dependency system is convention-based. Markdown partials introduce explicit, file-level include edges.
If those edges are not tracked, then:
3. Cycle handling / recursive rendering
Once nested partials are allowed, cycle protection becomes mandatory.
Without explicit ancestry tracking, recursive includes can fail badly or produce opaque errors.
4. Scope creep into full component behavior
It will be tempting to extend this into:
n- mountable client islands
That should be resisted in the first implementation. The value of this feature is that it stays content-first and server-rendered.
5. Interaction with existing component/template data expectations
Depending on how HTML built-in render functions receive data, there may be overlap with the broader question of how inline HTML constructs see outer template data.
This should be handled narrowly for
markdownpartials rather than using the feature as implicit justification for broader component-data behavior changes.Non-Goals for v1
.mdfiles full Nue componentsRecommendation
Proceed with this feature as a Markdown Partial implementation with:
<markdown>in HTML[markdown]in Nuemark.mdtargets only in v1That gives users a meaningful content-composition feature without forcing Markdown into the existing HTML component runtime model.