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 @@
+
+
+