Skip to content

Commit e00e051

Browse files
committed
[react-dom] Keep controlled <select> value on form reset
1 parent 2740158 commit e00e051

File tree

1 file changed

+21
-12
lines changed

1 file changed

+21
-12
lines changed

packages/react-dom-bindings/src/client/ReactDOMSelect.js

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -80,29 +80,38 @@ function updateOptions(
8080
if (options[i].selected !== selected) {
8181
options[i].selected = selected;
8282
}
83-
if (selected && setDefaultSelected) {
84-
options[i].defaultSelected = true;
83+
if (setDefaultSelected) {
84+
options[i].defaultSelected = selected;
8585
}
8686
}
8787
} else {
8888
// Do not set `select.value` as exact behavior isn't consistent across all
8989
// browsers for all cases.
9090
const selectedValue = toString(getToStringValue(propValue));
91-
let defaultSelected = null;
91+
// We use null as a signal that an option is explicitly selected.
92+
let defaultSelected: void | null | HTMLOptionElement = undefined;
9293
for (let i = 0; i < options.length; i++) {
93-
if (options[i].value === selectedValue) {
94+
const selected = options[i].value === selectedValue;
95+
if (setDefaultSelected) {
96+
options[i].defaultSelected = selected;
97+
}
98+
if (selected) {
9499
options[i].selected = true;
95-
if (setDefaultSelected) {
96-
options[i].defaultSelected = true;
100+
defaultSelected = null;
101+
if (!setDefaultSelected) {
102+
// We need to loop through all options when updating defaultSelected.
103+
// Otherwise multiple options may end up with defaultSelected=true
104+
// and resetting won't work properly.
105+
return;
97106
}
98-
return;
99107
}
100-
if (defaultSelected === null && !options[i].disabled) {
108+
if (defaultSelected === undefined && !options[i].disabled) {
101109
defaultSelected = options[i];
102110
}
103111
}
104-
if (defaultSelected !== null) {
112+
if (defaultSelected !== null && defaultSelected !== undefined) {
105113
defaultSelected.selected = true;
114+
defaultSelected.defaultSelected = true;
106115
}
107116
}
108117
}
@@ -152,7 +161,7 @@ export function initSelect(
152161
const node: HTMLSelectElement = (element: any);
153162
node.multiple = !!multiple;
154163
if (value != null) {
155-
updateOptions(node, !!multiple, value, false);
164+
updateOptions(node, !!multiple, value, true);
156165
} else if (defaultValue != null) {
157166
updateOptions(node, !!multiple, defaultValue, true);
158167
}
@@ -221,7 +230,7 @@ export function updateSelect(
221230
const node: HTMLSelectElement = (element: any);
222231

223232
if (value != null) {
224-
updateOptions(node, !!multiple, value, false);
233+
updateOptions(node, !!multiple, value, true);
225234
} else if (!!wasMultiple !== !!multiple) {
226235
// For simplicity, reapply `defaultValue` if `multiple` is toggled.
227236
if (defaultValue != null) {
@@ -238,6 +247,6 @@ export function restoreControlledSelectState(element: Element, props: Object) {
238247
const value = props.value;
239248

240249
if (value != null) {
241-
updateOptions(node, !!props.multiple, value, false);
250+
updateOptions(node, !!props.multiple, value, true);
242251
}
243252
}

0 commit comments

Comments
 (0)