diff --git a/.changeset/good-plums-type.md b/.changeset/good-plums-type.md
new file mode 100644
index 000000000000..9a1d8965f395
--- /dev/null
+++ b/.changeset/good-plums-type.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: set correct component context when rendering snippets
diff --git a/packages/svelte/src/compiler/phases/2-analyze/index.js b/packages/svelte/src/compiler/phases/2-analyze/index.js
index 64d35f398930..c7b92d4af0ed 100644
--- a/packages/svelte/src/compiler/phases/2-analyze/index.js
+++ b/packages/svelte/src/compiler/phases/2-analyze/index.js
@@ -384,6 +384,7 @@ export function analyze_component(root, source, options) {
reactive_statements: new Map(),
binding_groups: new Map(),
slot_names: new Map(),
+ top_level_snippets: [],
css: {
ast: root.css,
hash: root.css
diff --git a/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js b/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js
index 6e9c17faab98..5259712266c2 100644
--- a/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js
+++ b/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js
@@ -354,6 +354,7 @@ export function client_component(source, analysis, options) {
...store_setup,
...legacy_reactive_declarations,
...group_binding_declarations,
+ ...analysis.top_level_snippets,
.../** @type {import('estree').Statement[]} */ (instance.body),
analysis.runes || !analysis.needs_context ? b.empty : b.stmt(b.call('$.init')),
.../** @type {import('estree').Statement[]} */ (template.body)
diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js
index c508414f72ce..eca72e16b8be 100644
--- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js
+++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js
@@ -835,10 +835,7 @@ function serialize_inline_component(node, component_name, context) {
if (slot_name === 'default') {
push_prop(
- b.init(
- 'children',
- context.state.options.dev ? b.call('$.add_snippet_symbol', slot_fn) : slot_fn
- )
+ b.init('children', context.state.options.dev ? b.call('$.wrap_snippet', slot_fn) : slot_fn)
);
} else {
serialized_slots.push(b.init(slot_name, slot_fn));
@@ -2566,16 +2563,20 @@ export const template_visitors = {
.../** @type {import('estree').BlockStatement} */ (context.visit(node.body)).body
]);
- const path = context.path;
- // If we're top-level, then we can create a function for the snippet so that it can be referenced
- // in the props declaration (default value pattern).
- if (path.length === 1 && path[0].type === 'Fragment') {
- context.state.init.push(b.function_declaration(node.expression, args, body));
- } else {
- context.state.init.push(b.const(node.expression, b.arrow(args, body)));
- }
+ /** @type {import('estree').Expression} */
+ let snippet = b.arrow(args, body);
+
if (context.state.options.dev) {
- context.state.init.push(b.stmt(b.call('$.add_snippet_symbol', node.expression)));
+ snippet = b.call('$.wrap_snippet', snippet);
+ }
+
+ const declaration = b.var(node.expression, snippet);
+
+ // Top-level snippets are hoisted so they can be referenced in the `
+
+
diff --git a/packages/svelte/tests/runtime-runes/samples/non-local-mutation-with-binding-4/Outer.svelte b/packages/svelte/tests/runtime-runes/samples/non-local-mutation-with-binding-4/Outer.svelte
new file mode 100644
index 000000000000..a49a7392846a
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/non-local-mutation-with-binding-4/Outer.svelte
@@ -0,0 +1,5 @@
+
+
+{@render children?.()}
diff --git a/packages/svelte/tests/runtime-runes/samples/non-local-mutation-with-binding-4/_config.js b/packages/svelte/tests/runtime-runes/samples/non-local-mutation-with-binding-4/_config.js
new file mode 100644
index 000000000000..8f9cf55514ab
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/non-local-mutation-with-binding-4/_config.js
@@ -0,0 +1,11 @@
+import { test } from '../../test';
+
+export default test({
+ html: ``,
+
+ compileOptions: {
+ dev: true
+ },
+
+ warnings: []
+});
diff --git a/packages/svelte/tests/runtime-runes/samples/non-local-mutation-with-binding-4/main.svelte b/packages/svelte/tests/runtime-runes/samples/non-local-mutation-with-binding-4/main.svelte
new file mode 100644
index 000000000000..bbf7026cefde
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/non-local-mutation-with-binding-4/main.svelte
@@ -0,0 +1,10 @@
+
+
+
+
+
diff --git a/packages/svelte/tests/snapshot/samples/bind-component-snippet/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/bind-component-snippet/_expected/client/index.svelte.js
index 4f78c872b526..87f74847c905 100644
--- a/packages/svelte/tests/snapshot/samples/bind-component-snippet/_expected/client/index.svelte.js
+++ b/packages/svelte/tests/snapshot/samples/bind-component-snippet/_expected/client/index.svelte.js
@@ -6,16 +6,15 @@ var root_1 = $.template(`Something`, 1);
var root = $.template(` `, 1);
export default function Bind_component_snippet($$anchor) {
- let value = $.source('');
- const _snippet = snippet;
- var fragment_1 = root();
-
- function snippet($$anchor) {
+ var snippet = ($$anchor) => {
var fragment = root_1();
$.append($$anchor, fragment);
- }
+ };
+ let value = $.source('');
+ const _snippet = snippet;
+ var fragment_1 = root();
var node = $.first_child(fragment_1);
TextInput(node, {