Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

<select> dynamic <option> insertion doesn't match browser reality #7395

Open
dandclark opened this issue Dec 6, 2021 · 2 comments
Open

<select> dynamic <option> insertion doesn't match browser reality #7395

dandclark opened this issue Dec 6, 2021 · 2 comments

Comments

@dandclark
Copy link
Contributor

The spec for <select> has this to say about dynamic insertion of <option> elements:

If nodes are inserted or nodes are removed causing the list of options to gain or lose one or more option elements, or if an option element in the list of options asks for a reset, then, if the select element's multiple attribute is absent, the user agent must run the first applicable set of steps from the following list:

  • If the select element's display size is 1, and no option elements in the select element's list of options have their selectedness set to true

    • Set the selectedness of the first option element in the list of options in tree order that is not disabled, if any, to true.
  • If two or more option elements in the select element's list of options have their selectedness set to true

    • Set the selectedness of all but the last option element with its selectedness set to true in the list of options in tree order to false.

But this doesn't seem to match browser reality in Chromium, Firefox, or Safari for single-select when an option with selected set to true is dynamically inserted:

<select id="select1">
  <option>one</option>
  <option selected>two</option>
  <option>three</option>
</select>

<select id="select2">
  <option>one</option>
  <option selected>two</option>
  <option>three</option>
</select>

<script>
let select1 = document.querySelector("#select1");
let option1 = document.createElement("option");
option1.innerText = "new";
option1.selected = true;
select1.prepend(option1);

let select2 = document.querySelector("#select2");
let option2 = document.createElement("option");
option2.innerText = "new";
option2.selected = true;
select2.append(option2);
</script>

Per my reading of the spec, the last option in tree-order with selectedness == true should be the one that ends up selected. When the new option is inserted we match the case If two or more option elements in the select element's list of options have their selectedness set to true. Thus for select1, the selected option should be "two". For select2 it should be "new". But running this in Chromium/Firefox/Safari, both <select>s end up with "new" selected.

Live version of this test is here.

Since implementations seem to agree on their behavior, should the spec change to reflect this implementation reality? The behavior seems to be that when an <option> with selectedness == true is inserted under the <select>, that option becomes the selected one regardless of tree position relative to the old selected option(s). Or am I just reading the spec incorrectly?

@Kaiido
Copy link
Member

Kaiido commented Dec 7, 2021

Quite confusing indeed. Just two paragraphs above we have

If the multiple attribute is absent, whenever an option element in the select element's list of options has its selectedness set to true, and whenever an option element with its selectedness set to true is added to the select element's list of options, the user agent must set the selectedness of all the other option elements in its list of options to false.

Which does correspond to what implementations do in your tests.
However I must admit I don't see how we can ever fall in this "If two or more option elements in the select element's list of options have their selectedness set to true" case.
As per my quote, setting the selectedness to true will unselect all the other options, so no way to trigger this by changing the selectedness of an element that's already in the list, and if an already "selected" element is added to the list then all others options will have their selectedness set to false, so apparently no way to trigger this by appending new elements either.

If there is a case where this could happen I think it might be worth to explicitly call it out.

@domenic
Copy link
Member

domenic commented Dec 13, 2021

Yeah, I agree the spec should be updated here. And there is indeed some confusing overlap between the paragraph you quote and the one @Kaiido quotes, and how they interact.

Honestly the hardest part of fixing this would be avoiding the temptation to yak-shave and restructure that section entirely... it's mixing together so many different things (user interaction requirements, DOM mutation responses, multiple vs. not, ...). Any help is welcome, from surgical fixes up to a restructure and rewrite.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

4 participants