Skip to content

Commit 2e8b57b

Browse files
fix: render selected options for <select multiple> with an array value on the server (#18720)
Follow-up to #18591. --------- Co-authored-by: Simon Holthausen <simon.holthausen@vercel.com>
1 parent 864de81 commit 2e8b57b

4 files changed

Lines changed: 43 additions & 19 deletions

File tree

packages/svelte/src/internal/server/renderer.js

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ export class Renderer {
8989
* State that is local to the branch it is declared in.
9090
* It will be shallow-copied to all children.
9191
*
92-
* @type {{ select_value: any, select_default_multiple: boolean }}
92+
* @type {{ select_value: any, multiple: boolean }}
9393
*/
9494
local;
9595

@@ -101,9 +101,7 @@ export class Renderer {
101101
this.#parent = parent;
102102

103103
this.global = global;
104-
this.local = parent
105-
? { ...parent.local }
106-
: { select_value: undefined, select_default_multiple: false };
104+
this.local = parent ? { ...parent.local } : { select_value: undefined, multiple: false };
107105
this.type = parent ? parent.type : 'body';
108106
}
109107

@@ -346,8 +344,7 @@ export class Renderer {
346344
this.push(`<select${attributes(select_attrs, css_hash, classes, styles, flags)}>`);
347345
this.child((renderer) => {
348346
renderer.local.select_value = value === undefined ? defaultValue : value;
349-
renderer.local.select_default_multiple =
350-
value === undefined && Boolean(select_attrs.multiple);
347+
renderer.local.multiple = !!select_attrs.multiple;
351348
fn(renderer);
352349
});
353350
this.push(`${is_rich ? '<!>' : ''}</select>`);
@@ -375,10 +372,14 @@ export class Renderer {
375372
value = attrs.value;
376373
}
377374

375+
var select_value = this.local.select_value;
376+
378377
if (
379-
this.local.select_default_multiple
380-
? is_array(this.local.select_value) && this.local.select_value.includes(value)
381-
: value === this.local.select_value
378+
// Super edge-case, but theoretically someone could use arrays with non-multiple selects,
379+
// so we gotta check for the multiple attribute presence, too.
380+
this.local.multiple && is_array(select_value)
381+
? select_value.includes(value)
382+
: value === select_value
382383
) {
383384
renderer.#out.push(' selected=""');
384385
}

packages/svelte/tests/runtime-legacy/samples/binding-select-multiple/_config.js

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,30 @@ export default test({
66
return { selected: ['two', 'three'] };
77
},
88

9-
html: `
9+
ssrHtml: `
1010
<select multiple>
1111
<option>one</option>
12-
<option>two</option>
13-
<option>three</option>
12+
<option selected>two</option>
13+
<option selected>three</option>
1414
</select>
1515
1616
<p>selected: two, three</p>
1717
`,
1818

19-
test({ assert, component, target, window }) {
19+
test({ assert, component, target, window, variant }) {
20+
const selected = variant === 'hydrate' ? ' selected' : '';
21+
assert.htmlEqual(
22+
target.innerHTML,
23+
`
24+
<select multiple>
25+
<option>one</option>
26+
<option${selected}>two</option>
27+
<option${selected}>three</option>
28+
</select>
29+
30+
<p>selected: two, three</p>
31+
`
32+
);
2033
const select = target.querySelector('select');
2134
ok(select);
2235
const options = [...target.querySelectorAll('option')];
@@ -33,8 +46,8 @@ export default test({
3346
`
3447
<select multiple>
3548
<option>one</option>
36-
<option>two</option>
37-
<option>three</option>
49+
<option${selected}>two</option>
50+
<option${selected}>three</option>
3851
</select>
3952
4053
<p>selected: three</p>
@@ -51,8 +64,8 @@ export default test({
5164
`
5265
<select multiple>
5366
<option>one</option>
54-
<option>two</option>
55-
<option>three</option>
67+
<option${selected}>two</option>
68+
<option${selected}>three</option>
5669
</select>
5770
5871
<p>selected: one, three</p>
@@ -70,8 +83,8 @@ export default test({
7083
`
7184
<select multiple>
7285
<option>one</option>
73-
<option>two</option>
74-
<option>three</option>
86+
<option${selected}>two</option>
87+
<option${selected}>three</option>
7588
</select>
7689
7790
<p>selected: one, two</p>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<select multiple="">
2+
<option selected="" value="a">A</option>
3+
<option value="b">B</option>
4+
<option selected="" value="c">C</option>
5+
</select>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<select multiple value={['a', 'c']}>
2+
<option value="a">A</option>
3+
<option value="b">B</option>
4+
<option value="c">C</option>
5+
</select>

0 commit comments

Comments
 (0)