diff --git a/.changeset/fuzzy-zoos-repeat.md b/.changeset/fuzzy-zoos-repeat.md
new file mode 100644
index 0000000000..3fb3f0502e
--- /dev/null
+++ b/.changeset/fuzzy-zoos-repeat.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: value/checked not correctly set using spread
diff --git a/packages/svelte/src/internal/client/dom/elements/attributes.js b/packages/svelte/src/internal/client/dom/elements/attributes.js
index 4a0f0cea0e..987d1f2086 100644
--- a/packages/svelte/src/internal/client/dom/elements/attributes.js
+++ b/packages/svelte/src/internal/client/dom/elements/attributes.js
@@ -399,15 +399,18 @@ export function set_attributes(
if (name === 'value' || name === 'checked') {
// removing value/checked also removes defaultValue/defaultChecked — preserve
let input = /** @type {HTMLInputElement} */ (element);
-
+ const use_default = prev === undefined;
if (name === 'value') {
- let prev = input.defaultValue;
+ let previous = input.defaultValue;
input.removeAttribute(name);
- input.defaultValue = prev;
+ input.defaultValue = previous;
+ // @ts-ignore
+ input.value = input.__value = use_default ? previous : null;
} else {
- let prev = input.defaultChecked;
+ let previous = input.defaultChecked;
input.removeAttribute(name);
- input.defaultChecked = prev;
+ input.defaultChecked = previous;
+ input.checked = use_default ? previous : false;
}
} else {
element.removeAttribute(key);
diff --git a/packages/svelte/tests/runtime-runes/samples/attribute-spread-input/_config.js b/packages/svelte/tests/runtime-runes/samples/attribute-spread-input/_config.js
new file mode 100644
index 0000000000..ab94125503
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/attribute-spread-input/_config.js
@@ -0,0 +1,33 @@
+import { flushSync } from 'svelte';
+import { test } from '../../test';
+
+export default test({
+ async test({ target, assert }) {
+ // Test for https://github.com/sveltejs/svelte/issues/15237
+ const [setValues, clearValue] = target.querySelectorAll('button');
+ const [text1, text2, check1, check2] = target.querySelectorAll('input');
+
+ assert.equal(text1.value, '');
+ assert.equal(text2.value, '');
+ assert.equal(check1.checked, false);
+ assert.equal(check2.checked, false);
+
+ flushSync(() => {
+ setValues.click();
+ });
+
+ assert.equal(text1.value, 'message');
+ assert.equal(text2.value, 'message');
+ assert.equal(check1.checked, true);
+ assert.equal(check2.checked, true);
+
+ flushSync(() => {
+ clearValue.click();
+ });
+
+ assert.equal(text1.value, '');
+ assert.equal(text2.value, '');
+ assert.equal(check1.checked, false);
+ assert.equal(check2.checked, false);
+ }
+});
diff --git a/packages/svelte/tests/runtime-runes/samples/attribute-spread-input/main.svelte b/packages/svelte/tests/runtime-runes/samples/attribute-spread-input/main.svelte
new file mode 100644
index 0000000000..4bb4365ee2
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/attribute-spread-input/main.svelte
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+