blitz-dom: `Node::outer_html` drops comments and template contents and writes `<p />`
Generated from repros/blitz-dom-outer-html-serialization/README.md when the site was built at 7aa23e2.
What niso does
Section titled “What niso does”niso serializes innerHTML/outerHTML itself with the HTML fragment serialization algorithm
(crates/niso-core/src/serialize.rs, called from crates/niso-core/src/api.rs:1356-1379; commit 8e05962
“Serialize HTML with the spec algorithm, including comments and template contents” replaced calls to
Node::outer_html()). Svelte 5’s templates are innerHTML round-trips through <template> with comment
anchors, so all of the bugs below break it.
Expected vs actual
Section titled “Expected vs actual”Node::write_outer_html_in_style (packages/blitz-dom/src/node/serialize.rs:117-226):
- Comments are dropped (
NodeData::Comment { .. } => {}). <template>contents are dropped: the parser puts them in the detachedtemplate_contentsfragment (mutator.rs:189-219), and the serializer only walkschildren.- Every element without children is written as
<x />. For non-void HTML elements that is not self-closing when parsed back, so<p />followed by siblings swallows them. Void elements are written<br />instead of<br>(harmless when reparsed, but not the spec’s output). - U+00A0 is written raw instead of
.
expected: <div id="t" title="a"b"><!--c--><template><b>x</b></template><p></p><br><span>a b</span></div>actual: <div id="t" title="a"b"><template /><p /><br /><span>a b</span></div>(the space in a b is a raw U+00A0.)
Not counted as bugs: there is no inner_html (niso writes children itself), and outer_html of the Document node
is empty; those are missing APIs. niso’s tree.rs (pre-insert validity, adopt, etc.) is likewise spec logic blitz’s
DocumentMutator does not offer rather than a blitz bug, so it has no repro.
CARGO_TARGET_DIR=~/.capy/work/repro-target cargo runExit status 1 while the bug reproduces, 0 once fixed. On Ubuntu, blitz needs sudo apt-get install -y libfontconfig-dev pkg-config.
Upstream main
Section titled “Upstream main”Reproduces. Blitz main was at be60597f67b3cece0456d26e8d7ff5a88600bbc5 when tested (2026-11-08, git ls-remote https://github.com/DioxusLabs/blitz HEAD), the same commit niso pins, so the pinned result is also the main result.
Also tested against open PR DioxusLabs/blitz#1204 (head 9c4db3a0ef23424f58bb87b952ca3ec1555c4141, path
dependency on a local checkout): it fixes 3 and 4, but comments and template contents are still dropped:
actual: <div id="t" title="a"b"><template></template><p></p><br><span>a b</span></div>Existing issue or PR
Section titled “Existing issue or PR”- https://github.com/DioxusLabs/blitz/pull/1204 (open, “Serialize outerHTML/innerHTML as HTML”): void elements,
end tags for empty elements,
. Does not cover comments or template contents. - https://github.com/DioxusLabs/blitz/pull/986 (merged, “Escape text and write spec attribute names when serializing nodes”): earlier escaping work.
- No issue or PR found for comments or template contents.
Issue text
Section titled “Issue text”Title: Node::outer_html drops comments and <template> contents
Body:
write_outer_html_in_style skips NodeData::Comment and never visits a template’s template_contents
fragment, so serializing any subtree with comments or templates loses them. Frameworks that build DOM from
innerHTML/<template> with comment markers (Svelte 5, Lit, Vue’s static hoisting) cannot round-trip through it.
(#1204 fixes the <p /> and parts of the same function but not these.)
use blitz_dom::DocumentConfig;use blitz_html::HtmlDocument;
fn main() { let doc = HtmlDocument::from_html( r#"<!DOCTYPE html><html><body><div id="t"><!--c--><template><b>x</b></template><p></p><br><span>a b</span></div></body></html>"#, DocumentConfig::default(), ); let id = doc.get_element_by_id("t").unwrap(); println!("{}", doc.get_node(id).unwrap().outer_html()); // expected: <div id="t"><!--c--><template><b>x</b></template><p></p><br><span>a b</span></div> // actual: <div id="t"><template /><p /><br /><span>a\u{a0}b</span></div>}Tested at be60597f67b3cece0456d26e8d7ff5a88600bbc5 and with #1204 applied. Fix: write <!-- + contents + --> for comments, and for an HTML
template element serialize the children of template_contents instead of children, per
https://html.spec.whatwg.org/#serialising-html-fragments.