diff --git a/packages/svelte/src/internal/client/dom/elements/attributes.js b/packages/svelte/src/internal/client/dom/elements/attributes.js index dd57d4be46..0276069eee 100644 --- a/packages/svelte/src/internal/client/dom/elements/attributes.js +++ b/packages/svelte/src/internal/client/dom/elements/attributes.js @@ -60,6 +60,7 @@ export function remove_input_defaults(input) { export function set_value(element, value) { // @ts-expect-error var attributes = (element.__attributes ??= {}); + if ( attributes.value === (attributes.value = @@ -68,8 +69,10 @@ export function set_value(element, value) { // @ts-expect-error // `progress` elements always need their value set when its `0` (element.value === value && (value !== 0 || element.nodeName !== 'PROGRESS')) - ) + ) { return; + } + // @ts-expect-error element.value = value; } @@ -82,7 +85,15 @@ export function set_checked(element, checked) { // @ts-expect-error var attributes = (element.__attributes ??= {}); - if (attributes.checked === (attributes.checked = checked)) return; + if ( + attributes.checked === + (attributes.checked = + // treat null and undefined the same for the initial value + checked ?? undefined) + ) { + return; + } + // @ts-expect-error element.checked = checked; } diff --git a/packages/svelte/tests/runtime-runes/samples/form-default-value/_config.js b/packages/svelte/tests/runtime-runes/samples/form-default-value/_config.js index d8245cef4b..5ef72aaa8e 100644 --- a/packages/svelte/tests/runtime-runes/samples/form-default-value/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/form-default-value/_config.js @@ -37,8 +37,9 @@ export default test({ const after_reset = []; const reset = /** @type {HTMLInputElement} */ (target.querySelector('input[type=reset]')); - const [test1, test2, test3, test4, test5, test6, test13] = target.querySelectorAll('div'); - const [test7, test8, test9, test10] = target.querySelectorAll('select'); + const [test1, test2, test3, test4, test5, test6, test7, test14] = + target.querySelectorAll('div'); + const [test8, test9, test10, test11] = target.querySelectorAll('select'); const [ test1_span, test2_span, @@ -49,7 +50,8 @@ export default test({ test7_span, test8_span, test9_span, - test10_span + test10_span, + test11_span ] = target.querySelectorAll('span'); { @@ -133,6 +135,13 @@ export default test({ { /** @type {NodeListOf} */ const inputs = test5.querySelectorAll('input'); + check_inputs(inputs, 'checked', true); + assert.htmlEqual(test5_span.innerHTML, 'true true'); + + for (const input of inputs) { + set_input(input, 'checked', false); + } + flushSync(); check_inputs(inputs, 'checked', false); assert.htmlEqual(test5_span.innerHTML, 'false false'); @@ -145,86 +154,98 @@ export default test({ { /** @type {NodeListOf} */ const inputs = test6.querySelectorAll('input'); + check_inputs(inputs, 'checked', false); + assert.htmlEqual(test6_span.innerHTML, 'false false'); + + after_reset.push(() => { + check_inputs(inputs, 'checked', true); + assert.htmlEqual(test6_span.innerHTML, 'true true'); + }); + } + + { + /** @type {NodeListOf} */ + const inputs = test7.querySelectorAll('input'); check_inputs(inputs, 'checked', true); - assert.htmlEqual(test6_span.innerHTML, 'true'); + assert.htmlEqual(test7_span.innerHTML, 'true'); after_reset.push(() => { check_inputs(inputs, 'checked', false); - assert.htmlEqual(test6_span.innerHTML, 'false'); + assert.htmlEqual(test7_span.innerHTML, 'false'); }); } { /** @type {NodeListOf} */ - const options = test7.querySelectorAll('option'); + const options = test8.querySelectorAll('option'); check_inputs(options, 'selected', [false, true, false]); - assert.htmlEqual(test7_span.innerHTML, 'b'); + assert.htmlEqual(test8_span.innerHTML, 'b'); select_option(options[2]); flushSync(); check_inputs(options, 'selected', [false, false, true]); - assert.htmlEqual(test7_span.innerHTML, 'c'); + assert.htmlEqual(test8_span.innerHTML, 'c'); after_reset.push(() => { check_inputs(options, 'selected', [false, true, false]); - assert.htmlEqual(test7_span.innerHTML, 'b'); + assert.htmlEqual(test8_span.innerHTML, 'b'); }); } { /** @type {NodeListOf} */ - const options = test8.querySelectorAll('option'); + const options = test9.querySelectorAll('option'); check_inputs(options, 'selected', [false, true, false]); - assert.htmlEqual(test8_span.innerHTML, 'b'); + assert.htmlEqual(test9_span.innerHTML, 'b'); select_option(options[2]); flushSync(); check_inputs(options, 'selected', [false, false, true]); - assert.htmlEqual(test8_span.innerHTML, 'c'); + assert.htmlEqual(test9_span.innerHTML, 'c'); after_reset.push(() => { check_inputs(options, 'selected', [false, true, false]); - assert.htmlEqual(test8_span.innerHTML, 'b'); + assert.htmlEqual(test9_span.innerHTML, 'b'); }); } { /** @type {NodeListOf} */ - const options = test9.querySelectorAll('option'); + const options = test10.querySelectorAll('option'); check_inputs(options, 'selected', [false, false, true]); - assert.htmlEqual(test9_span.innerHTML, 'c'); + assert.htmlEqual(test10_span.innerHTML, 'c'); select_option(options[0]); flushSync(); check_inputs(options, 'selected', [true, false, false]); - assert.htmlEqual(test9_span.innerHTML, 'a'); + assert.htmlEqual(test10_span.innerHTML, 'a'); after_reset.push(() => { check_inputs(options, 'selected', [false, true, false]); - assert.htmlEqual(test9_span.innerHTML, 'b'); + assert.htmlEqual(test10_span.innerHTML, 'b'); }); } { /** @type {NodeListOf} */ - const options = test10.querySelectorAll('option'); + const options = test11.querySelectorAll('option'); check_inputs(options, 'selected', [false, false, true]); - assert.htmlEqual(test10_span.innerHTML, 'c'); + assert.htmlEqual(test11_span.innerHTML, 'c'); select_option(options[0]); flushSync(); check_inputs(options, 'selected', [true, false, false]); - assert.htmlEqual(test10_span.innerHTML, 'a'); + assert.htmlEqual(test11_span.innerHTML, 'a'); after_reset.push(() => { check_inputs(options, 'selected', [false, true, false]); - assert.htmlEqual(test10_span.innerHTML, 'b'); + assert.htmlEqual(test11_span.innerHTML, 'b'); }); } { /** @type {NodeListOf} */ - const inputs = test13.querySelectorAll('input, textarea'); + const inputs = test14.querySelectorAll('input, textarea'); assert.equal(inputs[0].value, 'x'); assert.equal(/** @type {HTMLInputElement} */ (inputs[1]).checked, true); assert.equal(inputs[2].value, 'x'); diff --git a/packages/svelte/tests/runtime-runes/samples/form-default-value/main.svelte b/packages/svelte/tests/runtime-runes/samples/form-default-value/main.svelte index ff7324b441..4d6a1a00b8 100644 --- a/packages/svelte/tests/runtime-runes/samples/form-default-value/main.svelte +++ b/packages/svelte/tests/runtime-runes/samples/form-default-value/main.svelte @@ -28,12 +28,16 @@ let checked2 = $state(); let checked3 = $state(); let checked4 = $state(); - let checked5 = $state(false); - let checked6 = $state(false); - let checked7 = $state(false); - let checked8 = $state(false); - let checked9 = $state(true); - let checked10 = $state(true); + let checked5 = $state(null); + let checked6 = $state(null); + let checked7 = $state(null); + let checked8 = $state(null); + let checked9 = $state(false); + let checked10 = $state(false); + let checked11 = $state(false); + let checked12 = $state(false); + let checked13 = $state(true); + let checked14 = $state(true); let selected1 = $state(); @@ -94,7 +98,7 @@ - +
@@ -102,10 +106,18 @@
- +
- - + + + + +
+ + +
+ +
@@ -158,7 +170,7 @@

Static values

-
+
@@ -174,11 +186,12 @@ {value17} {value20} {value22} {value24} {checked2} {checked4} {checked6} {checked8} - {checked10} - {selected1} - {selected2} - {selected3} - {selected4} - {selected5} - {selected6} + {checked10} {checked12} + {checked14} + {selected1} + {selected2} + {selected3} + {selected4} + {selected5} + {selected6}