diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index 531208c476..0ad46618fa 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -803,15 +803,31 @@ export default class ElementWrapper extends Wrapper { const fn = this.node.namespace === namespaces.svg ? x`@set_svg_attributes` : x`@set_attributes`; - block.chunks.hydrate.push( - b`${fn}(${this.var}, ${data});` - ); + if (this.node.is_dynamic_element) { + // call attribute bindings for custom element if tag is custom element + const tag = this.node.tag_expr.manipulate(block); + const attr_update = b` + if (/-/.test(${tag})) { + @set_custom_element_data_map(${this.var}, ${data}); + } else { + ${fn}(${this.var}, ${data}); + }`; + block.chunks.hydrate.push(attr_update); + block.chunks.update.push(b` + ${data} = @get_spread_update(${levels}, [${updates}]); + ${attr_update}` + ); + } else { + block.chunks.hydrate.push( + b`${fn}(${this.var}, ${data});` + ); - block.chunks.update.push(b` - ${fn}(${this.var}, ${data} = @get_spread_update(${levels}, [ - ${updates} - ])); - `); + block.chunks.update.push(b` + ${fn}(${this.var}, ${data} = @get_spread_update(${levels}, [ + ${updates} + ])); + `); + } // handle edge cases for elements if (this.node.name === 'select') { diff --git a/src/runtime/internal/dom.ts b/src/runtime/internal/dom.ts index 090b8925e1..d359513eb4 100644 --- a/src/runtime/internal/dom.ts +++ b/src/runtime/internal/dom.ts @@ -316,6 +316,12 @@ export function set_svg_attributes(node: Element & ElementCSSInlineStyle, attrib } } +export function set_custom_element_data_map(node, data_map: Record) { + Object.keys(data_map).forEach((key) => { + set_custom_element_data(node, key, data_map[key]); + }); +} + export function set_custom_element_data(node, prop, value) { if (prop in node) { node[prop] = typeof node[prop] === 'boolean' && value === '' ? true : value; diff --git a/test/runtime-puppeteer/samples/dynamic-element-custom-element/_config.js b/test/runtime-puppeteer/samples/dynamic-element-custom-element/_config.js new file mode 100644 index 0000000000..64b362a702 --- /dev/null +++ b/test/runtime-puppeteer/samples/dynamic-element-custom-element/_config.js @@ -0,0 +1,47 @@ +export default { + skip_if_ssr: true, + props: { + tag: 'my-custom-element', + name: null + }, + html: ` + Hello null! + Hello null! + `, + + test({ assert, component, target }) { + component.name = undefined; + assert.htmlEqual( + target.innerHTML, + `Hello undefined! + Hello undefined!` + ); + + component.name = 'foo'; + assert.htmlEqual( + target.innerHTML, + `Hello foo! + Hello foo!` + ); + + component.tag = null; + assert.htmlEqual( + target.innerHTML, + 'Hello foo!' + ); + + component.tag = 'div'; + assert.htmlEqual( + target.innerHTML, + `
+ Hello foo!` + ); + + component.tag = 'my-custom-element'; + assert.htmlEqual( + target.innerHTML, + `Hello foo! + Hello foo!` + ); + } +}; diff --git a/test/runtime-puppeteer/samples/dynamic-element-custom-element/main.svelte b/test/runtime-puppeteer/samples/dynamic-element-custom-element/main.svelte new file mode 100644 index 0000000000..81e29895d7 --- /dev/null +++ b/test/runtime-puppeteer/samples/dynamic-element-custom-element/main.svelte @@ -0,0 +1,32 @@ + + + +