Skip to content

Commit aa15a64

Browse files
lidlancadummdidumm
andauthored
fix: account for <template> tag in {@html} (#7364)
Ensure innerHTML for template is done on template element fixes #7315 fixes #7319 --------- Co-authored-by: Simon H <[email protected]>
1 parent dc7fd76 commit aa15a64

File tree

3 files changed

+19
-5
lines changed

3 files changed

+19
-5
lines changed

src/runtime/internal/dom.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -698,7 +698,7 @@ export class HtmlTag {
698698
// html tag nodes
699699
n: ChildNode[];
700700
// target
701-
t: HTMLElement | SVGElement;
701+
t: HTMLElement | SVGElement | DocumentFragment;
702702
// anchor
703703
a: HTMLElement | SVGElement;
704704

@@ -718,8 +718,9 @@ export class HtmlTag {
718718
) {
719719
if (!this.e) {
720720
if (this.is_svg) this.e = svg_element(target.nodeName as keyof SVGElementTagNameMap);
721-
else this.e = element(target.nodeName as keyof HTMLElementTagNameMap);
722-
this.t = target;
721+
/** #7364 target for <template> may be provided as #document-fragment(11) */
722+
else this.e = element((target.nodeType === 11 ? 'TEMPLATE' : target.nodeName) as keyof HTMLElementTagNameMap);
723+
this.t = target.tagName !== 'TEMPLATE' ? target : (target as HTMLTemplateElement).content;
723724
this.c(html);
724725
}
725726

@@ -728,7 +729,7 @@ export class HtmlTag {
728729

729730
h(html: string) {
730731
this.e.innerHTML = html;
731-
this.n = Array.from(this.e.childNodes);
732+
this.n = Array.from(this.e.nodeName === 'TEMPLATE' ? (this.e as HTMLTemplateElement).content.childNodes : this.e.childNodes);
732733
}
733734

734735
i(anchor) {

test/runtime/samples/template/_config.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export default {
66
<div>foo</div>
77
</template>
88
<template id="t2">123</template>
9+
<template id="t3">1<b>B</b>1</template>
910
`,
1011

1112
test({ assert, target }) {
@@ -27,5 +28,16 @@ export default {
2728
assert.equal(template2.content.firstChild.textContent, '123');
2829
assert.htmlEqual(template2.innerHTML, '123');
2930

31+
const template3 = target.querySelector('#t3');
32+
assert.equal(template3.childNodes.length, 0);
33+
assert.equal(template3.content.childNodes.length, 3);
34+
// test: (with hydration from ssr rendered html)
35+
// out of order render.
36+
// <template>1{@html '2'}3</template> may render as <template>321</template> for ssr+hydration case.
37+
// we bypass it by using symmetric siblings. hence <template> is not fully stable for this edge case.
38+
assert.equal(template3.content.childNodes[0].textContent, '1');
39+
assert.equal(template3.content.childNodes[1].outerHTML, '<b>B</b>');
40+
assert.equal(template3.content.childNodes[2].textContent, '1');
41+
3042
}
3143
};
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<template id="t1">
22
<div>foo</div>
33
</template>
4-
<template id="t2">123</template>
4+
<template id="t2">123</template>
5+
<template id="t3">1{@html '<b>B</b>'}1</template>

0 commit comments

Comments
 (0)