diff --git a/.changeset/fifty-masks-give.md b/.changeset/fifty-masks-give.md
new file mode 100644
index 000000000000..c555a7a34b09
--- /dev/null
+++ b/.changeset/fifty-masks-give.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: run render functions for dynamic void elements
diff --git a/packages/svelte/src/internal/client/dom/blocks/svelte-element.js b/packages/svelte/src/internal/client/dom/blocks/svelte-element.js
index bb660209e13b..1972ee4cb78b 100644
--- a/packages/svelte/src/internal/client/dom/blocks/svelte-element.js
+++ b/packages/svelte/src/internal/client/dom/blocks/svelte-element.js
@@ -40,7 +40,7 @@ function swap_block_dom(effect, from, to) {
* @param {Comment} anchor
* @param {() => string} get_tag
* @param {boolean} is_svg
- * @param {undefined | ((element: Element, anchor: Node) => void)} render_fn,
+ * @param {undefined | ((element: Element, anchor: Node | null) => void)} render_fn,
* @param {undefined | (() => string)} get_namespace
* @returns {void}
*/
@@ -115,13 +115,11 @@ export function element(anchor, get_tag, is_svg, render_fn, get_namespace) {
? element.firstChild && hydrate_anchor(/** @type {Comment} */ (element.firstChild))
: element.appendChild(empty());
- if (child_anchor) {
- // `child_anchor` can be undefined if this is a void element with children,
- // i.e. `...`. This is
- // user error, but we warn on it elsewhere (in dev) so here we just
- // silently ignore it
- render_fn(element, child_anchor);
- }
+ // `child_anchor` is undefined if this is a void element, but we still
+ // need to call `render_fn` in order to run actions etc. If the element
+ // contains children, it's a user error (which is warned on elsewhere)
+ // and the DOM will be silently discarded
+ render_fn(element, child_anchor);
}
anchor.before(element);
diff --git a/packages/svelte/tests/runtime-runes/samples/action-void-element/_config.js b/packages/svelte/tests/runtime-runes/samples/action-void-element/_config.js
new file mode 100644
index 000000000000..3ebd8d126a67
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/action-void-element/_config.js
@@ -0,0 +1,11 @@
+import { test } from '../../test';
+
+export default test({
+ html: ``,
+
+ async test({ assert, target }) {
+ const inputs = target.querySelectorAll('input');
+ assert.equal(inputs[0].value, 'set from action');
+ assert.equal(inputs[1].value, 'set from action');
+ }
+});
diff --git a/packages/svelte/tests/runtime-runes/samples/action-void-element/main.svelte b/packages/svelte/tests/runtime-runes/samples/action-void-element/main.svelte
new file mode 100644
index 000000000000..e9a833d6ac76
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/action-void-element/main.svelte
@@ -0,0 +1,9 @@
+
+
+
+