whatwg / html

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

Stylable `<select>` element #9799

Open josepharhar opened 10 months ago

josepharhar commented 10 months ago

Edit: I am proposing stylability and other improvements for the <select> element rather than a new element based on the discussion in this issue. The explainer has been updated.

Original description below:

I'd like to propose the new <selectlist> element, as described in this explainer: https://open-ui.org/components/selectlist/

This element still has a lot of open issues as listed in openui, but for now I'd at least like to know if people agree that this is a problem worth solving. The problem is that the existing <select> element is not customizable in terms of appearance or behavior which leads web authors to build their own and miss out of the usability, accessibility, and autofill features of builtin elements like <select>.

zcorpan commented 10 months ago

@whatwg/forms

rohankaushal123 commented 9 months ago

I'd like to work on this issue @zcorpan

annevk commented 9 months ago

Thank you for bringing this proposal to the WHATWG Joey! I thought this would be a good opportunity to outline how colleagues and I feel about extending HTML in this area. In particular, we feel that new and existing form controls:

We understand that the select element can’t address a variety of scenarios due to parser limitations, but the select element could address them in combination with the datalist element. One of our big worries with complete duplication is that we end up not solving the problems with the existing controls and that the duplicated controls will have a variety of shortcomings the older controls did not have.

(Aside: https://github.com/whatwg/html/issues/5791 seems very related to this issue.)

hsivonen commented 9 months ago

I think the explainer doesn't explain the need for a new element in a convincing way, because the multiple examples look addressable in the context of select: flags are addressable by emoji instead of image files, subheadings by the label attribute of optgroup, and color and font-level styling seems feasible without a new element.

(From off-explainer examples, I gather that the ambition level of the feature is much higher than the explainer makes appear.)

josepharhar commented 9 months ago

Thanks for taking a look and discussing with colleagues Anne!

Should look the same as the operating system controls by default.

If we made appearance:none or a new appearance value like appearance:base as discussed here and here have a standardized style, then the default appearance:auto appearance could look the same as OS controls. That would be up to each UA to decide, as it is currently for all other form controls.

Should be fully styleable by web developers.

Agreed! Styleability is the primary driving use case for the current proposal.

Should generally attempt to follow existing HTML element patterns.

Agreed! Domenic left some feedback in this vein and we completely revamped the proposal to use existing HTML element patterns by using new tag names instead of slot and behavior attributes.

Should work on a wide variety of platforms, including those with very small screens, no mouse or touch, etc.

Agreed! Existing elements conform to this by letting the browser/OS provide a native picker which unfortunately can’t be styled or customized by web developers, right? It was recommended that we let the browser use native pickers for selectlist on mobile here. Ideally developers would be enabled to make their own pickers that work on these platforms when they want to as well.

Should be fully accessible.

Agreed! This is also a core requirement for the proposal. I have been working closely with accessibility experts participating in OpenUI to ensure that the accessibility mappings and keyboard behaviors follow the current best practices in ARIA.

Should not have any l10n or i18n shortcomings.

Agreed! The content is fully customizable/replaceable, so it should be localizable and internationalizable, right? The only thing I can think of is supporting right-to-left and vertical writing modes when rendering where the listbox popup goes, which is something we are doing for other form control elements and we can easily do via Anchor Positioning for selectlist. Is there anything else you had in mind here?

Should not be redundant with existing HTML form controls.

We understand that the select element can’t address a variety of scenarios due to parser limitations, but the select element could address them in combination with the datalist element

It sounds like yall would prefer to reuse the existing <select> element instead of creating a new tag name. Am I correct? As you mentioned, we can’t have the new content model exist inside the <select> element due to parser rules, but we could try to do something with how datalist works by adding attributes to <select> which refer to the other elements we want to use, which would perhaps look like <select list=my-listbox button=my-button>. However, I don’t think this would work well. This works for <input list=datalist> because datalists are just used to host text data without doing actual rendering. Since we are actually trying to render an authored <listbox> or <button> element inside the select/selectlist, we don’t have the machinery in the browser to render them from an arbitrary location in the DOM. ShadowDOM is perfect for this and is how existing builtin elements like details and summary work. It is also easier and more idiomatic (like <option> and <summary>) for the new listbox and button elements to know when they should have special behavior for selectlist because they can look at their parent context rather than having to keep track of which select element has an attribute pointing at them. A preview of the State of HTML survey I’ve seen also lists <datalist> as a top developer pain point, which perhaps alludes that the ergonomics of referring to a separate element aren’t great.

One of our big worries with complete duplication is that we end up not solving the problems with the existing controls and that the duplicated controls will have a variety of shortcomings the older controls did not have.

I agree that duplication should be avoided. Selectlist is not a complete duplicate of select. <select> can draw outside the bounds of the browser window, and <selectlist> has a completely different rendering model that allows full customization. If it were possible to shoehorn into <select> that would be nice, but it looks infeasible.

josepharhar commented 9 months ago

I think the explainer doesn't explain the need for a new element in a convincing way, because the multiple examples look addressable in the context of select: flags are addressable by emoji instead of image files, subheadings by the label attribute of optgroup, and color and font-level styling seems feasible without a new element.

Thanks for the feedback! I am improving the examples here: https://github.com/openui/open-ui/pull/918

lukewarlow commented 9 months ago

flags are addressable by emoji instead of image files

I just wanted to point out Windows doesn't provide flag emojis so this specific example is a good use case for needing images not emoji.

annevk commented 9 months ago

Existing elements conform to this by letting the browser/OS provide a native picker which unfortunately can’t be styled or customized by web developers, right?

If you use appearance:none they can usually be styled. And we should do more work here to add something akin to appearance:base to make that more ergonomic for web developers. I don't think the solution should be adding new elements that don't have platform theming by default as that would make the HTML language inconsistent.

ShadowDOM is perfect for this and is how existing builtin elements like details and summary work.

For <datalist id=options> we'd have to clone the options into the select element's shadow tree for rendering purposes, I think, much in the same way we probably have to clone one of the options as the selected option. As long as this happens in the internal shadow tree it's largely not observable and should be okay.

It would also have the benefit of having a consistent design with <input type=text list=options>, so we'd tackle combo boxes at the same time (or at least make it possible to reuse the design for them). Since the <datalist> continues to mainly serve as a source of data I don't think there's any need to track what element is pointing to it.

(There are some challenges here with how to match these options and their elements from CSS, but that seems like a surmountable problem.)

I haven't looked at survey in detail, but I'd assume that if <datalist> is mentioned as a pain point it would mainly be around not being able to style it, which is something we'd have to tackle for combo boxes and select alike.

josepharhar commented 8 months ago

I’ve been discussing with @annevk and @pxlcoder about how to move forward here, and we have reached agreement on some things. Please correct if I misrepresent anything!

lukewarlow commented 8 months ago

I'm concerned by the implications of the multiple attribute. How does it work with the new parsing?

That being said I am excited by the progressive enhancement possibilities.

gregwhitworth commented 8 months ago

If you use appearance:none they can usually be styled. And we should do more work here to add something akin to appearance:base to make that more ergonomic for web developers.

@annevk The majority you cannot and it isn't solely about styling but also extending them. While select may be able to be re-used; one of the benefits of introducing the new elements that are interoperable by default and not OS platform styled does make the platform consistent rather than trying to retro-fit all the build-in UI controls. I think we may want to fork this into a more generic issue specific to the introduction of new elements as I'm curious how your assertion holds up for input type=switch that not only allows styling but extensibility without a new element; type=file, type=progress, etc?

Using <datalist> as a child of <select> will work to replace the listbox with custom content This makes sense to me outside of my position that we should introduce a new element, not a new CSS attribute to solve this problem as it's not just about styling

@josepharhar @annevk so will this likewise have the child of <selectedoption> and ability to modify the initial shadow DOM?

josepharhar commented 7 months ago

@josepharhar @annevk so will this likewise have the child of <selectedoption> and ability to modify the initial shadow DOM?

The idea (as I see it) is to still have a <selectedoption> element that can be a child of the <button> element we use to replace the <select>'s default button.

The UA shadowroot will certainly adapt if and when needed to support slotting in and replacing the default button and listbox.

Does that answer your question? I'm not sure if I understood it well.

josepharhar commented 6 months ago

Adding agenda+ to move this to stage 1

josepharhar commented 6 months ago

I updated the explainer to be <select> instead of <selectlist>: https://open-ui.org/components/selectlist/

josepharhar commented 6 months ago

I was just talking to @una and she said that using a <datalist> which accepts rich content in <select> would be inconsistent because <datalist> won't accept rich content when used with <input>, so it would be better to create a new element like <listbox> for this. If, however, we eventually make <datalist> with <input> accept rich content, then it would not be inconsistent.

It would also have the benefit of having a consistent design with <input type=text list=options>, so we'd tackle combo boxes at the same time (or at least make it possible to reuse the design for them). Since the <datalist> continues to mainly serve as a source of data I don't think there's any need to track what element is pointing to it.

I believe these positions are aligned and that we should improve <datalist> for <input type=text>.

I don't think that <input type=text> is powerful enough to handle the use cases described here, but hopefully we can still improve <datalist> anyway: https://open-ui.org/components/combobox.explainer/

argyleink commented 6 months ago

I'm a big fan of improving <datalist>! I've long asked for it to be styleable so it can match my designs.

See demo here: https://codepen.io/argyleink/pen/GRemrav

All of a sudden, datalist is a hero and very valuable. Which is not how it's currently regarded today.

The above demo, notice how the rich content of the datalist doesn't break the parser, and the label attribute properly populates both the presentation of the option and the value as the selected value.

If datalist gets the ability to show rich content and can be styled, the work left for <select> is to teach it to how to be a <select list=""> AND teach datalist to support the [multiple] attribute. It might also mean allowing uniquely that <select> can have an implicit datalist (also in the demo), this way older browsers still render select as it always has.

This improves all form inputs with a list attribute! Appeasing old and new browsers, but enabling rich presentation of options for newer parsers.


for combobox, I feel like that needs a new input type, as the value it holds is no longer a string, but an array of objects, both in the value and in the DOM. imagine pointing an <input type=combobox list="contacts" />, and each contact chosen is turned into a little chip inside the input. datalist again being just a presentation of options, styleable by authors, returning values for inputs to use.

lukewarlow commented 6 months ago

The idea is that the combobox proposal would be that way to do input + datalist properly.

lukewarlow commented 6 months ago

@argyleink combobox doesn't have to be an array it has the single Vs multi concept that select has

argyleink commented 6 months ago

@argyleink combobox doesn't have to be an array it has the single Vs multi concept that select has

sure, but it's contents need to be nodes and not strings tho right? it has children, where input type text doesnt

brechtDR commented 6 months ago

I agree that we could make the datalist a bit more lovable.

I do want to note though that one thing I loved about the previous proposal was to style the "listbox" and "button" using a pseudo element.

Reason: as a developer we sometimes need to work with third parties - for example - payment providers. It is common that when working with such external tools, we only get to add some CSS and cannot touch the HTML. Just saying that this is a feature that will be missed and could've been loved by many.

If that idea is dead. I can understand that. But I did want to note the importance of having that capability of pseudo elements.

josepharhar commented 5 months ago

OpenUI resolved on using an attribute instead of datalist/button to opt in to the new parser behavior: https://github.com/openui/open-ui/issues/985#issuecomment-1922141513

This would mean that the following would parse all elements:

<select bikeshed>
  <option>
    <img src="one.jpg">
    one
  <option>
  <option>
    <img src="two.jpg">
    two
  </option>
</select>

In order to make the element fully featured the same way that the original selectlist element proposal was, this would likely mean that the UA shadowroot will have a default datalist/listbox popup that will be used if the author doesn't provide one. However, if the author does provide one, then it will be used instead. So the following would also be valid and result in a datalist popover:

<select bikeshed>
  <datalist>
    <option>...</option>
    ...
  </datalist>
</select>

Again to be fully featured like the selectlist element, we would likely also add pseudo elements to the select element like ::button and ::listbox or ::datalist to target the the default button if the author doesn't provide one or the author provided button if there is one, and same for the datalist.

OpenUI is working to provide a list of reasons why using an attribute like this is better. I'd be interested to hear thoughts from @domenic @annevk and @smaug----. Adding agenda+ to discuss.

annevk commented 5 months ago

I tried reading through those minutes, but it's not really clear to me why a new attribute is needed. How is

<select bikeshed>
  <option>
    <img src="one.jpg">

different from

<select>
  <datalist>
    <option>
      <img src="one.jpg">

? In fact, allowing img might well be something we can do without bikeshed="" or <datalist>, similar to how we did hr.

domenic commented 5 months ago

Switching parsing mode for an element's descendants based on an attribute seems pretty unusual and I don't know if we have any precedent for it. I liked the old proposal in that the parser always behaved the same way.

It's also a bit strange that in the new proposal, it sounds like <select bikeshed><datalist>... stuff ...</datalist></select> is the same as <select bikeshed>... stuff ...</select>. It's not unprecedented (cf. <table> and <tbody>), but I think it's a bit of a confusing experience for developers, and it definitely makes one wonder why we need the bikeshed instead of just always doing <select><datalist>... stuff ...</datalist></select>.

Can you say more on why the group decided to move away from the previous consensus? The thread seems very long so any kind of summarization effort would be helpful.

gregwhitworth commented 5 months ago

After re-reading the minutes the key reasons come down to these two bullet points:

To @domenic point we discussed table quite a bit as an example and we even discussed making it so that it would go back and do cleanup and @mfreed7 noted that this wasn't a desired path, here are those minutes so there didn't seem much desire to do table type fixup:

flackr: i have a point on that which may be relevant - we could make the construction behavior similar to tables - the browser could make flackr: I was suggesting, if the concern is not knowing whether you have these elements we could make it so that the attribute implictly creates the parts and those are still targetable masonf: that's foster parenting and it's not fun masonf: there are XSS issues, etc luke: it causes hydration mishaps

@annevk said the following:

I tried reading through those minutes, but it's not really clear to me why a new attribute is needed. How is ... code example ... different from ... code example ...

It seems to me as though this debate is six of one, half a dozen of the other at this point. @josepharhar already called out that he doubted WHATWG would be in agreement on this and if you all prefer the children it would be good to understand why you all prefer that path to the attribute.

In fact, allowing img might well be something we can do without bikeshed="" or <datalist>, similar to how we did hr.

This may possibly be an orthogonal issue but my only concern would be back compat.

brechtDR commented 5 months ago

@annevk said:

I tried reading through those minutes, but it's not really clear to me why a new attribute is needed.

One thing i'd like to note Is that by using an attribute, the authors could easily just opt in to custom style the datalist or options(to for example: add an image inside of it). They could do this without explicitly having to add the button to trigger the change.

It provides a much better developer experience and ease of tutoring. Changing an HTML element based on it's children is not really common and would also increase the chances for developer error.

annevk commented 5 months ago

Opting into custom styling is to be done through CSS (appearance:base, appearance:base-select, or whatever we decide for that). That doesn't require markup and using markup would bring us back to the days of <font>. Not good. The new markup is only there to allow for richer data structures.

lukewarlow commented 5 months ago

I think Brecht means doing select[base] { appearance: base-select } rather than select:has(datalist)

annevk commented 5 months ago

I don't understand the use case. Why would you not want to style all your select elements equally? We're not drawing a line in the sand here, we're extending the select element so it can do more things.

brechtDR commented 5 months ago

Why would you not want to style all your select elements equally?

I don't understand why you should be forced to style everything. Maybe you just want to create a little shadow or border on the datalist, but want the default button / marker styling. Or even the other way around, Maybe you want to go the extra mile with the button beyond the capabilities of what you can do with a <select> now, but want to leave other elements as they are.

annevk commented 5 months ago

And why would that not be possible?

brechtDR commented 5 months ago

And why would that not be possible?

Isn't it the case that when you want to change the behavior (old select vs styleable) based on the children, it should contain all the children (button + datalist)?

(forgot to mention that indeed, @lukewarlow that is my point)

annevk commented 5 months ago

Again, both should be styleable and that shouldn't depend on their children. As I said in https://github.com/whatwg/html/issues/9799#issuecomment-1926411811 the new markup just gives access to richer data structures.

mfreed7 commented 5 months ago

So I just wanted to comment because I listened to the entire OpenUI discussion carefully, and I feel like there were very good points made by developers in the room.

To be clear, we're talking specifically about the trigger for changing the Shadow DOM structure of the <select> element. I.e. how the implementation decides whether it can support all of the new behaviors, such as:

So the folks in the room nearly unanimously pushed for an attribute vs. the "add the right kind of element as a child" approach, and the strongest reason was that it was the most parallel to other things on the platform. Developers were familiar with adding an attribute to an element to change its behavior. Examples include <template shadowrootmode> (which also happens to change parser behavior), <input type=whatever>, and <element popover>. Nobody could think of an example in the platform where adding a specific kind of child element changed the behavior so significantly for the parent element. And they all thought it would be confusing.

Having said that, either approach can be used to meet the use case. The question for the WHATWG spec editors is: what is the motivation for pushing for the child element approach, when it seems like the least familiar/parallel way to do it?

annevk commented 5 months ago

To me that does not seem like the right approach. That's still the line in the sand approach I referred to above. Showing options as a "popover" should purely be the result of appearance:bikeshed and apply to the <select> element as it stands today. The same goes for styling the currently-selected value. appearance:auto might not allow for that, but appearance:bikeshed does.

I'm not sure what's lacking about keyboard focus, and a11y, but it seems like that should also be a universal improvement.

brechtDR commented 5 months ago

@annevk said:

One of our big worries with complete duplication is that we end up not solving the problems with the existing controls and that the duplicated controls will have a variety of shortcomings the older controls did not have.

I just want to note that if this was one of the big worries, that it should be out of the way with an attribute as well.

It does feel as @mfreed7 mentioned that an attribute is likely the more natural pattern and that children deciding parser behaviour feels like an anti-pattern (declaring the intent twice, based on children). Parsing based on children could also lead to more author errors.

annevk commented 5 months ago

Why would it be out of the way with an attribute? An attribute as you all have envisioned creates the exact kind of mode switch we'd want to avoid.

I also don't follow what you're saying about the HTML parser. Perhaps you can describe the dilemma you see there in more concrete terms? The entire parser is structured around branching on tag names which is exactly what we'd be doing here. It wouldn't affect the parent one bit. And as I mentioned above it seems worthwhile investigating if we can allow things like <select><option><img> Some text</select> as well. No reason to require a <datalist> wrapper for a simple enhancement like that if we can avoid it.

brechtDR commented 5 months ago

Perhaps you can describe the dilemma you see there in more concrete terms?

It wouldn't affect the parent one bit.

Even if it doesn't really affect the parent in a technical way. It feels like I'd be telling the browser: I want a select, and then telling again in the children: I still want a select, but I want it styleable.

This is a complete different way than saying it inside of an attribute, that is what authors are used to. Example: I want an input and I want it to be a (type)date. aka: do those things for me based on the attribute.

This would be the equivalent that HTML should be like this:

<input type="date" /> vs <input><datalist>datepicker things</datalist></input>

<select bikeshed="bikeshed" /> vs <select><datalist>Now it's styleable</datalist></input>

Note that a select without any options in, still looks like a select. So in that case, children don't matter. Except it won't show a listbox.

(Exaggerated example, but wanted to make a point of how it feels)

I'm sorry if I can't give you any more technical reasons as I'm not a browser engineer, just an interested front-end developer (from what I hearing, both ideas are technical possible). I think I made my point as it is about consistency and general tutoring and feeling (yes, I believe that last one can be important). I would be utterly astonished if I would be the only developer thinking that way. Consider this "user feedback" from me. Maybe it could be asked around in developer communities a bit more.

annevk commented 5 months ago

You're still thinking of a mode switch. I'm saying that the select element we know today should be styleable as well in the exact same way. There's no before and after. The parser changes will enable developers to include more types of descendants, but that's it. Everything else should apply universally.

mfreed7 commented 5 months ago

You're still thinking of a mode switch. I'm saying that the select element we know today should be styleable as well in the exact same way. There's no before and after. The parser changes will enable developers to include more types of descendants, but that's it. Everything else should apply universally.

Given the very high usage of the existing select, with its current behaviors and idiosyncrasies, I would have serious doubts that we could just change all of them in a way that would be web compatible. There will need to be an opt-in.

gregwhitworth commented 5 months ago

Given the very high usage of the existing select, with its current behaviors and idiosyncrasies, I would have serious doubts that we could just change all of them in a way that would be web compatible. There will need to be an opt-in.

Agreed, there are bound to be sites that have complex content that currently we're throwing away for a variety of reasons and would not be backwards compatible.

An additional thing to consider is that this has to be contained within the viewport for security reasons. So there has to be some opt-in to get this new behavior.

I want a select, and then telling again in the children: I still want a select, but I want it styleable.

@brechtDR just a reminder that this solution we're discussing is solely for changing the DOM structure and its defined behaviors on that structure. The opt-in to make it base styles so that you can interoperabley style it will come from the CSS property.

annevk commented 5 months ago

The opt-in for different styling (within viewport) is appearance:bikeshed as now oft-repeated. And I think you have to be more concrete on the other roadblocks you see as it seems feasible to me and a much better model for web developers (and end users) overall.

lukewarlow commented 5 months ago

Isn't the viewport security model relevant to new parsing too? If we're allowing arbitrary content isn't that bad enough without full styling?

annevk commented 5 months ago

User agents get to decide what they propagate. I would imagine we would not let anything through but images and text. The richer data structure ultimately needs to be able to flatten to text options for a11y and cross-platform purposes anyway. That happens to also work well for native popup windows.

gregwhitworth commented 5 months ago

User agents get to decide what they propagate. I would imagine we would not let anything through but images and text. The richer data structure ultimately needs to be able to flatten to text options for a11y and cross-platform purposes anyway. That happens to also work well for native popup windows.

I feel like we're going in circles and possibly conflating the issues since you can theoretically add support for images on their own in select outside of aligning on a standardized DOM and behavior structure that would require it to be rendered within the viewport. So if we want to have that conversation maybe we should open a separate issue @annevk?

Regarding the below comment @annevk: Apologies I am still confused on the "line-in-the sand". We'll need to fix up the DOM in some manner that is backwards compatible. The Open UI CG decided on attribute, am I understanding your position correctly that you only want a CSS solution for that?

To me that does not seem like the right approach. That's still the line in the sand approach I referred to above. Showing options as a "popover" should purely be the result of appearance:bikeshed and apply to the