whatwg / html

HTML Standard
https://html.spec.whatwg.org/multipage/
Other
8.05k stars 2.64k forks source link

Opt-in for `<select>` customizability #5791

Open gregwhitworth opened 4 years ago

gregwhitworth commented 4 years ago

@dandclark opened this issue on the repo that contains the explainer for this. For context, we released an explainer that attempts to explain a web platform control definition for defining components going forward. This requires HTML modifications across the WHATWG but to keep this one scoped. Here is the outline from Dan in the initial issue:

It's necessary that control customizability be opt-in rather than on by default in order to not break compatibility with older > sites and to avoid issues where capabilities of the customizable controls be limited, e.g. the customizable <select> must > not escape the bounds of windows due to security concerns.

Opt-in for custom control behavior for type like will be done by introducing new elements, > e.g. <range>, for the customizable version, while will remain the same.

For <select>, since unlike <input> the parser does not prevent it from being parsed with child DOM nodes, we've proposed that it's not necessary to create a new element for it and we could instead do opt-in through an attribute like <select custom="">.

There are downsides to relying on an attribute though:

@mfreed7 pointed out that we'd need to deal with the fact that the custom attribute could be added/removed dynamically, which adds complexity. Parsing is particularly concerning here, since the attribute would change the parsing rules for the subtree of the <select>. Is there any scenario where a <select> could have script change it to custom when we're in the middle of parsing its subtree?

@travisleithead raised this specific concern about the dynamic case: consider a dynamically-created <select> (via document.createElement()), when the custom attribute must be set using setAttribute(). When should the transition to the custom behavior be applied? Applying it at the point of setAttribute() would be inconsistent with how other elements like <input type="range"> work when created dynamically; typically the transformation would occur when the element was appended to the DOM. But, this means that for a dynamically created <select>, the developer would have to wait until the <select> is appended to the DOM before calling attachShadow(), since attachShadow() throws for a non-custom <select>.

If we're minting new elements for all the customizable <input> types then it seems odd to do something different just for <select>.

On the other hand there are downsides to adding a new element for with the current + combination. E.g. work on a element. Developers are consistently tripped up by the fact that these similar controls have very different interfaces.

I am open to this and am worth discussing it, I'd like to resolve on the differences/naming as a combobox and select as the majority of component libs, etc leverage the name select even if they appear as a combobox. Which is why we were initially leaning towards a select derivative.

domenic commented 4 years ago

The naming will be a hard problem regardless, as you've mentioned; I don't have any strong opinions there.

But I do feel somewhat firmly that there needs to be unification of "select where you can type" and "select where you cannot type". And ideally that would be at the web-developer-facing level. For example, one element with an optional attribute.

Stated in terms of use cases, I think developers transitioning from a fixed set of inputs to a fixed set of inputs + optional free-form text (e.g., modernizing a gender form field) should be able to do so easily. Currently, to transition from <select> to <input> + <datalist>, they have to re-do all of their markup, change their CSS selectors, and probably update their JavaScript code if they use things like selectedIndex or options. It would be great if in the future they could just add an HTML attribute, or similar, without those extra changes.

gregwhitworth commented 4 years ago

@domenic yep - there is agreement here generally and we've discussed this in general here in Open UI as this is the primary request for <select> upon survey of 1400 webdevs and ~20 top web property partners in why they desire additional functionality. There are, to your point a desire to have a select solely be a button verse an actual input. I'll open a single issue on Open UI to discuss this (eg: should we bifurcate in control name solely to add an input rather than an element that behaves as button).

This is even more more odd with built in UA implementations as they allow type ahead functionality but don't show the actual user input which is just generally a bad UX. I think due to this I'd be more in favor of keeping the <select> name and updating the anatomy to contain an input by default since that is actually how it's behaving. I'll link the Open UI issue here later this evening.

mfreed7 commented 4 years ago

But I do feel somewhat firmly that there needs to be unification of "select where you can type" and "select where you cannot type". And ideally that would be at the web-developer-facing level. For example, one element with an optional attribute.

I just want to second this - the new element should unify these two use cases ("combo-box" and "drop-down") into a single control.

And I want to re-iterate my original comment: I think this should be a new element, not an attribute (which can be added and removed) on <select>. While I understand the argument that this new thing "looks" like the old <select>, there are many new behaviors that are incompatible with the old <select>:

  1. The (optional) ability to type anything, not just restricted to the set of options.
  2. Arbitrary HTML in options
  3. Customizable parts
  4. Pop-up that does not extend beyond the window bounds.

And inevitably there will be strange behaviors associated with adding or removing the opt-in attribute on <select> such as removal of selections, resetting of state, etc. And as mentioned by @travisleithead, there will be questions about the timing of when the new behavior takes effect.

Consider what would happen here, if we went the attribute-on-select route:

Sample #1:

const combobox = document.createElement('select');
document.body.appendChild(combobox);
combobox.addAttribute('newbehavior','true'); // Opt in!
combobox.innerHTML = '<option><img src="cat.jpg">Cat</option><option><img src="dog.jpg">Dog</option>';
// Here, we have a fancy, new <select> with images of cats and dogs

Sample #2:

const combobox = document.createElement('select');
document.body.appendChild(combobox);
combobox.innerHTML = '<option><img src="cat.jpg">Cat</option><option><img src="dog.jpg">Dog</option>';
combobox.addAttribute('newbehavior','true'); // Opt in, but a little late
// Boo! No images here, because we opted in after innerHTML, and the parser removed the <img> tags.
annevk commented 4 years ago

(Note that <input> + <datalist> also works for other controls (some in theory), e.g., range, color, and email.)

LeaVerou commented 3 years ago

I second the proposal for a new <combobox> element, or whatever it ends up being called to unify <select> and <input>+<datalist>.

A few thoughts:

zcorpan commented 3 years ago

Related issue: https://github.com/whatwg/html/issues/6733