diff --git a/.changeset/spotty-files-trade.md b/.changeset/spotty-files-trade.md
new file mode 100644
index 0000000000..39975b7a9a
--- /dev/null
+++ b/.changeset/spotty-files-trade.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: allow custom elements to receive async values as props
diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js
index 8dcd3c7d6f..1cf5abeb69 100644
--- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js
+++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js
@@ -664,14 +664,25 @@ function build_element_attribute_update(element, node_id, name, value, attribute
* @param {ComponentContext} context
*/
function build_custom_element_attribute_update_assignment(node_id, attribute, context) {
- const { value, has_state } = build_attribute_value(attribute.value, context);
+ const memoizer = new Memoizer();
+ const { value, has_state } = build_attribute_value(attribute.value, context, (value, metadata) =>
+ memoizer.add(value, metadata)
+ );
// don't lowercase name, as we set the element's property, which might be case sensitive
const call = b.call('$.set_custom_element_data', node_id, b.literal(attribute.name), value);
// this is different from other updates — it doesn't get grouped,
// because set_custom_element_data may not be idempotent
- const update = has_state ? b.call('$.template_effect', b.thunk(call)) : call;
+ const update = has_state
+ ? b.call(
+ '$.template_effect',
+ b.arrow(memoizer.apply(), call),
+ memoizer.sync_values(),
+ memoizer.async_values(),
+ memoizer.blockers()
+ )
+ : call;
context.state.init.push(b.stmt(update));
}
diff --git a/packages/svelte/tests/runtime-runes/samples/async-custom-element-attribute/_config.js b/packages/svelte/tests/runtime-runes/samples/async-custom-element-attribute/_config.js
new file mode 100644
index 0000000000..788573d7cf
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/async-custom-element-attribute/_config.js
@@ -0,0 +1,11 @@
+import { tick } from 'svelte';
+import { test } from '../../test';
+
+export default test({
+ async test({ target, assert }) {
+ await tick();
+ const [element] = target.querySelectorAll('async-custom-element');
+
+ assert.htmlEqual(element.innerHTML, `Hello foobar!`);
+ }
+});
diff --git a/packages/svelte/tests/runtime-runes/samples/async-custom-element-attribute/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-custom-element-attribute/main.svelte
new file mode 100644
index 0000000000..a047054069
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/async-custom-element-attribute/main.svelte
@@ -0,0 +1,41 @@
+
+
+
diff --git a/packages/svelte/tests/snapshot/samples/dynamic-attributes-casing/_expected/client/main.svelte.js b/packages/svelte/tests/snapshot/samples/dynamic-attributes-casing/_expected/client/main.svelte.js
index eafadfc2ea..799c9f2139 100644
--- a/packages/svelte/tests/snapshot/samples/dynamic-attributes-casing/_expected/client/main.svelte.js
+++ b/packages/svelte/tests/snapshot/samples/dynamic-attributes-casing/_expected/client/main.svelte.js
@@ -25,7 +25,7 @@ export default function Main($$anchor) {
var svg_1 = $.sibling(div_1, 2);
var custom_element_1 = $.sibling(svg_1, 2);
- $.template_effect(() => $.set_custom_element_data(custom_element_1, 'fooBar', y()));
+ $.template_effect(($0) => $.set_custom_element_data(custom_element_1, 'fooBar', $0), [() => y()]);
$.template_effect(
($0, $1) => {