diff --git a/.changeset/hot-frogs-melt.md b/.changeset/hot-frogs-melt.md
new file mode 100644
index 0000000000..95b3e0b4b4
--- /dev/null
+++ b/.changeset/hot-frogs-melt.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: use strict equality for key block comparisons in runes mode
diff --git a/packages/svelte/src/internal/client/dom/blocks/key.js b/packages/svelte/src/internal/client/dom/blocks/key.js
index 04b8ab403f..4a8b7b94fc 100644
--- a/packages/svelte/src/internal/client/dom/blocks/key.js
+++ b/packages/svelte/src/internal/client/dom/blocks/key.js
@@ -1,7 +1,8 @@
/** @import { Effect, TemplateNode } from '#client' */
import { UNINITIALIZED } from '../../../../constants.js';
import { block, branch, pause_effect } from '../../reactivity/effects.js';
-import { safe_not_equal } from '../../reactivity/equality.js';
+import { not_equal, safe_not_equal } from '../../reactivity/equality.js';
+import { is_runes } from '../../runtime.js';
import { hydrate_next, hydrate_node, hydrating } from '../hydration.js';
/**
@@ -24,8 +25,10 @@ export function key_block(node, get_key, render_fn) {
/** @type {Effect} */
var effect;
+ var changed = is_runes() ? not_equal : safe_not_equal;
+
block(() => {
- if (safe_not_equal(key, (key = get_key()))) {
+ if (changed(key, (key = get_key()))) {
if (effect) {
pause_effect(effect);
}
diff --git a/packages/svelte/src/internal/client/reactivity/equality.js b/packages/svelte/src/internal/client/reactivity/equality.js
index 751c8720f9..37a9994ab8 100644
--- a/packages/svelte/src/internal/client/reactivity/equality.js
+++ b/packages/svelte/src/internal/client/reactivity/equality.js
@@ -15,6 +15,15 @@ export function safe_not_equal(a, b) {
: a !== b || (a !== null && typeof a === 'object') || typeof a === 'function';
}
+/**
+ * @param {unknown} a
+ * @param {unknown} b
+ * @returns {boolean}
+ */
+export function not_equal(a, b) {
+ return a !== b;
+}
+
/** @type {Equals} */
export function safe_equals(value) {
return !safe_not_equal(value, this.v);
diff --git a/packages/svelte/tests/runtime-runes/samples/key-unchanged-value/_config.js b/packages/svelte/tests/runtime-runes/samples/key-unchanged-value/_config.js
new file mode 100644
index 0000000000..0c56330a3e
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/key-unchanged-value/_config.js
@@ -0,0 +1,13 @@
+import { flushSync } from 'svelte';
+import { test } from '../../test';
+
+export default test({
+ test({ assert, target, logs }) {
+ assert.deepEqual(logs, ['rendering']);
+
+ const btn = target.querySelector('button');
+ flushSync(() => btn?.click());
+
+ assert.deepEqual(logs, ['rendering']);
+ }
+});
diff --git a/packages/svelte/tests/runtime-runes/samples/key-unchanged-value/main.svelte b/packages/svelte/tests/runtime-runes/samples/key-unchanged-value/main.svelte
new file mode 100644
index 0000000000..47ecd20c10
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/key-unchanged-value/main.svelte
@@ -0,0 +1,10 @@
+
+
+
+
+{#key outer.inner}
+ {console.log('rendering')}
+{/key}