From eaa5ef565c982ce6b6b759c03eb9273a390af28d Mon Sep 17 00:00:00 2001 From: Your Name Date: Sat, 21 Feb 2026 18:04:02 -0800 Subject: [PATCH] Fix #13638: Svelte 5: Custom element's default not created when n --- .../client/dom/elements/custom-element.js | 14 +++++------ .../_config.js | 25 +++++++++++++++++++ .../main.svelte | 3 +++ 3 files changed, 35 insertions(+), 7 deletions(-) create mode 100644 packages/svelte/tests/runtime-browser/custom-elements-samples/no-initial-children-default-slot/_config.js create mode 100644 packages/svelte/tests/runtime-browser/custom-elements-samples/no-initial-children-default-slot/main.svelte diff --git a/packages/svelte/src/internal/client/dom/elements/custom-element.js b/packages/svelte/src/internal/client/dom/elements/custom-element.js index 8316fa7656..ccdd4c7e5c 100644 --- a/packages/svelte/src/internal/client/dom/elements/custom-element.js +++ b/packages/svelte/src/internal/client/dom/elements/custom-element.js @@ -114,13 +114,13 @@ if (typeof HTMLElement === 'function') { const $$slots = {}; const existing_slots = get_custom_elements_slots(this); for (const name of this.$$s) { - if (name in existing_slots) { - if (name === 'default' && !this.$$d.children) { - this.$$d.children = create_slot(name); - $$slots.default = true; - } else { - $$slots[name] = create_slot(name); - } + if (name === 'default' && !this.$$d.children) { + // Always create the default slot, even if no children are present initially, + // because children may be added dynamically later (fixes #13638) + this.$$d.children = create_slot(name); + $$slots.default = true; + } else if (name !== 'default' && name in existing_slots) { + $$slots[name] = create_slot(name); } } for (const attribute of this.attributes) { diff --git a/packages/svelte/tests/runtime-browser/custom-elements-samples/no-initial-children-default-slot/_config.js b/packages/svelte/tests/runtime-browser/custom-elements-samples/no-initial-children-default-slot/_config.js new file mode 100644 index 0000000000..cf0dca337f --- /dev/null +++ b/packages/svelte/tests/runtime-browser/custom-elements-samples/no-initial-children-default-slot/_config.js @@ -0,0 +1,25 @@ +import { test } from '../../assert'; +const tick = () => Promise.resolve(); + +export default test({ + async test({ assert, target }) { + // Mount the custom element with no initial children + target.innerHTML = ``; + await tick(); + + /** @type {any} */ + const ce = target.querySelector('my-widget'); + + // The default slot should be created even without initial children + assert.htmlEqual(ce.shadowRoot.innerHTML, ``); + + // Now add a child dynamically + const span = document.createElement('span'); + span.textContent = 'hello'; + ce.appendChild(span); + await tick(); + + // The slot element should still be present to render the dynamically added child + assert.htmlEqual(ce.shadowRoot.innerHTML, ``); + } +}); diff --git a/packages/svelte/tests/runtime-browser/custom-elements-samples/no-initial-children-default-slot/main.svelte b/packages/svelte/tests/runtime-browser/custom-elements-samples/no-initial-children-default-slot/main.svelte new file mode 100644 index 0000000000..9d462731ef --- /dev/null +++ b/packages/svelte/tests/runtime-browser/custom-elements-samples/no-initial-children-default-slot/main.svelte @@ -0,0 +1,3 @@ + + +