diff --git a/.changeset/smooth-windows-explain.md b/.changeset/smooth-windows-explain.md
new file mode 100644
index 0000000000..82f86945ea
--- /dev/null
+++ b/.changeset/smooth-windows-explain.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: ensure event handlers referencing $host are not hoisted
diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/Attribute.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/Attribute.js
index 85dfc6c67e..05ba0d486f 100644
--- a/packages/svelte/src/compiler/phases/2-analyze/visitors/Attribute.js
+++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/Attribute.js
@@ -155,8 +155,8 @@ function get_delegated_event(event_name, handler, context) {
const visited_references = new Set();
const scope = target_function.metadata.scope;
for (const [reference] of scope.references) {
- // Bail out if the arguments keyword is used
- if (reference === 'arguments') return unhoisted;
+ // Bail out if the arguments keyword is used or $host is referenced
+ if (reference === 'arguments' || reference === '$host') return unhoisted;
// Bail out if references a store subscription
if (scope.get(`$${reference}`)?.kind === 'store_sub') return unhoisted;
diff --git a/packages/svelte/tests/runtime-browser/custom-elements-samples/host-rune/_config.js b/packages/svelte/tests/runtime-browser/custom-elements-samples/host-rune/_config.js
index 0c2625dc20..bf09e864fa 100644
--- a/packages/svelte/tests/runtime-browser/custom-elements-samples/host-rune/_config.js
+++ b/packages/svelte/tests/runtime-browser/custom-elements-samples/host-rune/_config.js
@@ -14,11 +14,13 @@ export default test({
await tick();
- el.shadowRoot.querySelector('button').click();
- assert.deepEqual(events, ['greeting', 'hello']);
+ el.shadowRoot.querySelectorAll('button')[0].click();
+ el.shadowRoot.querySelectorAll('button')[1].click();
+ assert.deepEqual(events, ['greeting', 'hello', 'greeting', 'welcome']);
el.removeEventListener('greeting', handle_evt);
- el.shadowRoot.querySelector('button').click();
- assert.deepEqual(events, ['greeting', 'hello']);
+ el.shadowRoot.querySelectorAll('button')[0].click();
+ el.shadowRoot.querySelectorAll('button')[1].click();
+ assert.deepEqual(events, ['greeting', 'hello', 'greeting', 'welcome']);
}
});
diff --git a/packages/svelte/tests/runtime-browser/custom-elements-samples/host-rune/main.svelte b/packages/svelte/tests/runtime-browser/custom-elements-samples/host-rune/main.svelte
index 080e7a2740..2eddf77e9b 100644
--- a/packages/svelte/tests/runtime-browser/custom-elements-samples/host-rune/main.svelte
+++ b/packages/svelte/tests/runtime-browser/custom-elements-samples/host-rune/main.svelte
@@ -4,6 +4,11 @@
function greet(greeting) {
$host().dispatchEvent(new CustomEvent('greeting', { detail: greeting }))
}
+
+ function welcome() {
+ $host().dispatchEvent(new CustomEvent('greeting', { detail: 'welcome' }))
+ }
+