Email or username:

Password:

Forgot your password?
Jake Archibald

I'm excited that we're finally getting a customisable <select> on the web. However, there's one detail of it I'm really not sure about, and I'd like to hear your thoughts.

Have your say before it's too late πŸ˜€

jakearchibald.com/2024/how-sho

49 comments
kolya

@jaffathecake does that customisation overrule the OS-specific modal view of select on mobile devices?

Jake Archibald

@kolya yep. When you opt in, you get a cross-browser agreed default rendering that you can fully customise.

kolya

@jaffathecake good to know. I like that modal, it's good UX on mobile.

Jake Archibald

@kolya yeah, but the customisable select will be more accessible/usable than the random from-scratch implementations most developers come up with.

Luke

@kolya @jaffathecake worth also bearing in mind that because it's enabled via CSS you could choose *not* to enable the new picker on mobile if that's what you wanted in your design. You'd just lose the rich content.

Jake Archibald

@Lukew @kolya true! And you can even choose to customise the button, but leave the picker to the user-agent.

Dave 🧱 :cursor_pointer:

@jaffathecake @Lukew @kolya oh sweet! Nice to have this instead of hiding the select, but still allowing interaction, and showing a fake button

Dave 🧱 :cursor_pointer:

@jaffathecake it’s such a weird element, but I’m like you in thinking that I can’t see an alternate way to do it

Sjors Rijsdam

@jaffathecake I am always in favour of giving the author as much control as possible when it comes to these kinds of things. People will come up with wacky (good and bad) use cases which might get thwarted by assumptions about how stuff should behave, which leads to weird and possibly a11y hostile hacks.

Therefor I am in favour of an attribute on <selectedoption> that allows to opt in to certain behaviours.

Jake Archibald

@sjorsrijsdam of the four options in the post, which would you want to make available via this attribute?

Sjors Rijsdam

@jaffathecake I think one and two. The first would be the "manual" option where you can do your fancy use cases such as described in three and four and the second option could be the default/auto option.

Thomas Steiner :chrome:

@jaffathecake I'd vouch for "Option: Nothing by default, but provide a way to trigger an update" (jakearchibald.com/2024/how-sho). It feels like this would follow an 80:20 rule of being sufficient for 80% of regular usage of the element, and allow the 20% advanced usage of developers who know what they're doing full freedom. Since this is based on just gut feeling of expected usage, this choice could use backing by a developer survey (Do you expect to change an <option> when you use this new element?).

@jaffathecake I'd vouch for "Option: Nothing by default, but provide a way to trigger an update" (jakearchibald.com/2024/how-sho). It feels like this would follow an 80:20 rule of being sufficient for 80% of regular usage of the element, and allow the 20% advanced usage of developers who know what they're doing full freedom. Since this is based on just gut feeling of expected usage, this choice could...

Jake Archibald

@tomayac good feedback! I wanted to avoid a poll, as I wanted more detailed feedback, and I'm happy to collate it. This is pretty in the weeds and I worry that a poll might invite a lot of "I didn't read or understand the post but I'm going to pick an option anyway"

Thomas Steiner :chrome:

@jaffathecake Yes, definitely an issue with any survey (and elections). You might be able to tap into GDEs' opinions through @Una for maybe ensuring a certain quality bar. Or Microsoft MVPs etc. But yes, you'll be biased.

Markus Unterwaditzer

@jaffathecake it feels like anything but the first option is simply too "powerful" and invites abuse of <select> for other "DOM mirroring" purposes. I assume this issue only exists when JavaScript is used to mutate the DOM in the first place, so what's a little more JS to the user for implementing whatever behavior they actually want on top of Option 1?

groxx

@jaffathecake is there an article somewhere describing *why* select is hard to style? Structurally, not just due to current browser limitations, since this is a structural change?

I can definitely see why you don't like the copy approach, but… either I'm missing something or this seems like it would be rather easily handled by toggling an "is expanded" attribute on <select> and hiding non-selected things. I'm not seeing how the button and nesting solves problems proportional to what it causes.

Doug Parker

@jaffathecake Definitely not an expert here, but from a framework perspective, I think "Option: Nothing by default, but provide a way to trigger an update" is fine? In Angular you could do that like:

```
afterRender(() => {
selectedContent.resetOption();
});
```

(Could probably be more specific by effect-ing the selected option specifically.)

Either way of automatically resetting content seems bad for the performance and scheduling reasons you specified. Even if it was debounced, each framework schedules renders in different ways, so having it update at a different time is a recipe for bugs.

Targeted, automatic updates sounds cool, is that realistic to browser vendors though?

Honestly I expect most framework users would be better off not using `<selectedoption>` and just letting the framework manage rendering the content in multiple places. Frameworks already have decent solutions for that.

Maybe it's best to keep this simple and just expect more advanced use cases to skip the element entirely?

@jaffathecake Definitely not an expert here, but from a framework perspective, I think "Option: Nothing by default, but provide a way to trigger an update" is fine? In Angular you could do that like:

```
afterRender(() => {
selectedContent.resetOption();
});
```

(Could probably be more specific by effect-ing the selected option specifically.)

Doug Parker

@jaffathecake I wonder if there's a path to something like shadow DOM slots? In that context you can "project" an element from one location to another. What if the browser did a similar trick but which duplicated the element visually, while still only having one element in the DOM? Similar to how projected light DOM is not *in* the shadow DOM, it has a slot linked to the light DOM.

That feels similar to your last option but maybe would be more feasible to browser maintainers? It might require it's own spec independent of styled `<select>` though.

I wonder if that would help with something like `<canvas>`, since you could keep the same visual content in both copies, as there is only one source of truth. Doing this with an iframe sounds weird and scary though, so maybe it's a bad idea.

@jaffathecake I wonder if there's a path to something like shadow DOM slots? In that context you can "project" an element from one location to another. What if the browser did a similar trick but which duplicated the element visually, while still only having one element in the DOM? Similar to how projected light DOM is not *in* the shadow DOM, it has a slot linked to the light DOM.

Amelia Bellamy-Royds

@jaffathecake The last option (automatically linking the cloned subtree to the original) is basically what SVG use elements do. It seems completely doable if (and only if) the cloned shadow tree within the <selectedoption> element is read-only, which I'm assuming it would be.

Christian "Schepp" Schaefer

@AmeliaBR @jaffathecake I would favor that solution, too. And maybe we can generalize this approach, too, so that @kizu gets something new to play with (and crash the browser): front-end.social/@kizu/1132845

Jake Archibald

@AmeliaBR that's one of the weird things: the clone lives within the light DOM, not the shadow DOM. It has to to allow full styling.

Amelia Bellamy-Royds

@jaffathecake That is really weird & problematic, IMO. Is there any other case where the browser dynamically injects content in the light DOM?

Are styling hooks for shadow DOM still so bad that can't be adjusted?

Alternatively, again borrowing from SVG convention: The cloned element within a <use> brings with it style rules from its original context. For the selectedoption use case, you could then add a pseudoclass or host rule that matches the original element only in the cloned context.

Jake Archibald

@AmeliaBR I agree it's really weird. The only similar thing I can think of is contenteditable, but that's pretty different. But yeah, styling arbitrary shadow content is harrrrd.

Anne van Kesteren

@jaffathecake @AmeliaBR Styling is not the issue per se. Running script is.

Ollie Boermans

@AmeliaBR @jaffathecake doesn’t count as content – closest I can think of is tbody

```
<style>
tbody {
outline: solid tomato;
}
</style>
<table>
<tr><td>World</td></tr>
</table>
```

Jake Archibald

@ollicle @AmeliaBR yeahhhh, I think parser changes are different to interaction changes

Ollie Boermans

I can hear the nahhh balancing that yeahhh :emoji_squint:

Understood.

Axel Rauschmayer

@jaffathecake

Excerpt from your feed:

<title type="html"><![CDATA[How should <selectedoption> work?]]></title>

IINM, the angle brackets must be escaped: cyber.harvard.edu/rss/encoding

Jake Archibald

@rauschma ohhhhhhhhhhhhhhh this could explain the issues I'm seeing

Jake Archibald

@rauschma just pushed a fix for this. Should be there soon. Thanks for giving me the heads up!

luke_bennett_ :ziltoid:

@jaffathecake just a heads up that the angle brackets in the heading for this article are messing with my RSS reader πŸ˜…

Florian

@jaffathecake Out of curiosity, why are you using a button to trigger the select?
A number of semantic issues with custom selects are precisely because of this pattern, most notably that for a select, you generally want a name "pick a fruit" and a value "Apple", so the user can see what the select is for and what is selected without opening the dropdown. Buttons inherently cannot do this because buttons don't have values, so using a select that is appropriately labeled gives you this for free ... but not if you use a button to make the select happen :)

@jaffathecake Out of curiosity, why are you using a button to trigger the select?
A number of semantic issues with custom selects are precisely because of this pattern, most notably that for a select, you generally want a name "pick a fruit" and a value "Apple", so the user can see what the select is for and what is selected without opening the dropdown. Buttons inherently cannot do this because buttons don't have values, so using a select that is appropriately labeled gives you this for free ......

Jake Archibald

@zersiax values aren't supposed to be human readable. The button needs human readable text relating to it's action and current value. That's what this system provides.

Florian

@jaffathecake isn't the currently selected <option> visually distinguishable in a bog standard <select>? For reference, a screen reader will read a select as "label, combobox, current option". A button is more likely than not going to be "option, button collapsed/submenu", which loses the label, or "label, button collapsed/submenu" which loses the value. To fix this on a button you now have to cluge together the currently selected option and the button label with JS

Jake Archibald

@zersiax have you tested this? Remember that the browser knows that this button is a select popover activator.

Florian

@jaffathecake I have not, I am purely going on your code sample and have not had a chance to look into the specifics, it just struck me as odd from that perspective :) Do you happen to have a link to a codepen where this can be tried? No problem if not, also not intending to tell you you're wrong, just expressing a knee-jerk observation :)

Timothy Chien

@jaffathecake Is <option> continue to be text only? If so, it should be easy to duplicate the text in <selectedoption>.

Speak from my brief experience as an implementer, anything resembling <svg:use> opens a rather big can of worms.

Timothy Chien

@jaffathecake Got it. I hope by piggy backing on node.cloneNode(true) for the initial clone it would be less problematic than <svg:use> a <svg:foreignObject>. That was a memorable bug from fuzzying team πŸ˜….

The first option is not ergonomic IMO.

The last option is ... creative, not sure if it is achievable given the level of effort.

Speak of, why not generalize the light-DOM-deep-clone behavior? Maybe we should ship a `<html:clonefrom>` element instead 😝?

Marius Gundersen

@jaffathecake I would vote for doing nothing by default, and having the other scenarios solved with js. If you need it to do something advanced then bring a bit of javascript code to do that. It's much better than having to do something weird or performance problematic by default with only a complicated way to prevent it.

Jake Archibald

@gundersen as in, the first option in the article, or something even less?

Marius Gundersen

@jaffathecake first option, but maybe even without the resetOption(). It's not difficult to clone the option and replace the value manually, is it?

Jake Archibald

@gundersen that's fair. selectedOption.replaceChildren(...select.selectedOptions[0].cloneNode(true).childNodes)

Jake Archibald

Thanks to everyone who gave feedback on this. The group resolved on going with the first option in this post: Clone once when the selected option switches, and that's it.

Go Up