Skip to content

Commit ade8ef4

Browse files
committed
fix: bind null option and input values consistently
Null and undefined `value` bindings should always be set to an empty string. This allows native browser validation of `required` fields to work as expected with placeholder options. Resolves sveltejs#8312
1 parent ca53151 commit ade8ef4

File tree

4 files changed

+44
-4
lines changed

4 files changed

+44
-4
lines changed

src/compiler/compile/render_dom/wrappers/Element/Attribute.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ export default class AttributeWrapper extends BaseAttributeWrapper {
171171
}
172172

173173
if (is_indirectly_bound_value) {
174-
const update_value = b`${element.var}.value = ${element.var}.__value;`;
174+
const update_value = b`@set_input_value(${element.var}, ${element.var}.__value);`;
175175
block.chunks.hydrate.push(update_value);
176176

177177
updater = b`

test/js/samples/select-dynamic-value/expected.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import {
88
insert,
99
noop,
1010
safe_not_equal,
11-
select_option
11+
select_option,
12+
set_input_value
1213
} from "svelte/internal";
1314

1415
function create_fragment(ctx) {
@@ -24,9 +25,9 @@ function create_fragment(ctx) {
2425
option1 = element("option");
2526
option1.textContent = "2";
2627
option0.__value = "1";
27-
option0.value = option0.__value;
28+
set_input_value(option0, option0.__value);
2829
option1.__value = "2";
29-
option1.value = option1.__value;
30+
set_input_value(option1, option1.__value);
3031
},
3132
m(target, anchor) {
3233
insert(target, select, anchor);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
const items = [ { id: 'a' }, { id: 'b' } ];
2+
3+
export default {
4+
props: {
5+
foo: null,
6+
items
7+
},
8+
9+
test({ assert, component, target }) {
10+
const select = target.querySelector( 'select' );
11+
const options = target.querySelectorAll( 'option' );
12+
13+
assert.equal( options[0].selected, true );
14+
assert.equal( options[0].disabled, true );
15+
assert.equal( options[1].selected, false );
16+
assert.equal( options[1].disabled, false );
17+
18+
// placeholder option value must be blank string for native required field validation
19+
assert.equal( options[0].value, '' );
20+
assert.equal( select.checkValidity(), false );
21+
22+
component.foo = items[0];
23+
24+
assert.equal( options[0].selected, false );
25+
assert.equal( options[1].selected, true );
26+
assert.equal( select.checkValidity(), true );
27+
}
28+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<script>
2+
export let foo;
3+
export let items;
4+
</script>
5+
6+
<select bind:value={foo} required>
7+
<option value={null} disabled>Select an option</option>
8+
{#each items as item}
9+
<option value={item}>{item.id}</option>
10+
{/each}
11+
</select>

0 commit comments

Comments
 (0)