The new stylable <select> element 2024-10-08 We're finally getting a <select>
element we can fully control with CSS! A bunch of other stuff needed to be added to the platform to make it work, and the good news is we can use a lot of them independently of <select>
.
Resources:
Transcript Jake: I think I'm ready. I think I'm good to go. Surma: On a scale of 1 to 10, how rusty do you feel right now? Surma: You know, we're on a schedule with recording. Kinda. Jake: Are we? Surma: We've been pretty good. Like, plus minus a week or something. Surma: And yet I feel rustier than ever every time we do this. Jake: Yeah, I mean, we're a little bit behind compared to our usual schedule because, well, we both got ill. Surma: Yeah. Good. Jake: It wasn't Covid. Jake: Well, I don't know about that, because it knocked me out for a week. Jake: Like, I couldn't think properly. It had all the downsides of Covid, but without the validation. Surma: Ah, there is, like, a bit of, like, Surma: oh, it's Cove and everybody just nods in understanding, isn't it? Surma: I feel like, also, COVID is exempt from the man flu. Jake: Yeah. And, like, I know there are other illnesses out there. Jake: It's not like when Covid arrived, all the other illnesses felt so inadequate by comparison that they just vanished out of existence, right? Jake: So, I maybe had regular flu, right? I don't know. Jake: But I felt guilty not working because the little test was telling me, you're fine, mate. Surma: Any other flu. You get man flu labeled. Surma: Which, you know, maybe correctly so, I do not know. Jake: Exactly. Jake: Yes. Surma: But, yeah, I feel like, you're right! Surma: When you can say, I have COVID, everybody goes, Surma: oh, yeah, you just, you do your thing. You recover quickly. Jake: So, my start-up idea, and you can invest if you want, is a lateral flow test for everything. Jake: So, like, you get your two red stripes if... Surma: Any liquid hits the stick. Jake: Well, no, no, no, if you were ill enough to justifiably feel sorry for yourself and lie on your sofa. Surma: Right, so it's lateral flow for fragile masculinity. Jake: That's the rule. Surma: I like it. I'll invest. Jake: Exactly. Yeah. Jake: I guess it is a man flu or a person flu system. Jake: But, yeah, that just tells you, yeah, mate, you're ill. You're properly ill. Jake: Just take the day off. Go play PlayStation. Guilt-free. That's what I want. Surma: That seems, yeah, I want that in my life as well. Ship it. Surma: No, we should do an intro. Surma: You wanted to make this more professional. Surma: You told me off last time. Jake: Oh, we haven't even done the intro. Jake: Look, okay. Jake: Well, we've talked a bunch now. Surma: No, no, we're going to play the music. Jake: Are we going to edit this? Surma: And we're going to, people are going to hear me say, Surma: we should play the music now. Surma: Then we're going to play the music. Surma: And then we do the intro. Surma: We do like, you know, like some of the TV shows who, like, do the, Jake: No. Surma: like a little intro, then the actual theme plays. Surma: And then it goes like two weeks earlier. Surma: And then the actual story starts. Surma: And I think that's what we should do. Surma: Rope them in with a nonsense anecdote. Surma: That's totally how podcasts work, right? Jake: Fine. Roll the music. Jake: I heard my own voice going, do-do-do-do-do-do, like it was just nondescript music. Surma: Which music are you hearing in your head right now? Jake: You know that system you were talking about where, like, you know, they would have a bit of the show and then the intro sequence? Surma: Wow. Jake: And then that pattern actually came about from U.S. TV, where they would have an advert break straight after the intro. Surma: That's brutal. Jake: I know. I only learned this recently. I'm sure people in the U.S. were aware of it, but, you know. Jake: Anyway, you were about to do a professional intro, and I'm not going to stop you any longer. Surma: Ladies and gentlemen, welcome to OTMT. Surma: My name is Surma. Surma: And this is a podcast. Jake: My name is Jake. Jake: Yes, thanks, Shopify, for letting us do this, as usual. Surma: It is nice. Surma: Yeah. Jake: It's nice of them, isn't it? It's just nice. Everyone's nice. Surma: Yeah. Jake: Should we talk about the web now? Surma: Why not? Surma: Let's go. Jake: All right, all right. Jake: So, I wanted to talk about the new stylable select element on the web. Jake: It's something we've all wanted for years, 20 years, yeah. Surma: 20 years. Surma: Yeah. Jake: And it's actually close now, like, for real. Jake: Like, there's an implementation in Chrome Canary, and it's ready for feedback. Surma: Ooh. Surma: But how stylable is stylable? Jake: It's happening. Surma: What? Jake: Like, completely. Jake: I know, I know. Jake: And it's not without its rough edges and weirdness, and I will get to those, because it's fun. Jake: But I do think it's actually a great thing, and part of the story, the interesting part of the story for me, Jake: is all of the little lower-level features that we've gotten along the way. Surma: So they, they, they did the bill. Surma: It's not just, you know, like, Surma: Scrolling to facts. Surma: Boom, high level. Surma: Nothing in between. Surma: You only can link to scrolling and do stuff. Surma: But did they actually build the layers in between an X? Surma: And I'm giving us those as well. Surma: That is nice. Surma: So basically, because I know this work has been going on for a long time, the kind of Jake: Exactly. Jake: I've counted 10 lower-level features that are usable outside of select, Jake: but are used by the select, or you would typically use it with the select thing, Jake: and were probably created with it in mind. Surma: hope I would have hearing that is that the select element is the guinea pig and the next Surma: ones will maybe, hopefully come about quicker because now the lower level primitives have Jake: Yes. Jake: Absolutely, and there's patterns that have been established. Surma: already been designed and established. Surma: I have so many questions, but I'm going to let you set the scene first. Jake: Oh, I'll set the scene. Jake: The select element. Jake: Look, we've all made one. Jake: You've seen them. Jake: We've coded them. Jake: You get a select element, and then inside, you've got a bunch of options, Surma: It selects things. Surma: Oh, I used to use it quite a lot. Jake: potentially in opt groups, you know, or not, whatever. Jake: The user presses the select button thing, Jake: Really? Jake: Yeah. Jake: Yeah, that's why it's rubbish, because you have to ctrl or shift click, right? Jake: That's why no one uses it. Jake: Why is that? Surma: Well, not, I haven't done recently, but I know because it suddenly turns from like a Jake: Because it's a weird thing. Jake: It's weird. Jake: It's weird. Surma: drop down into a box and you can like control or shift click multiple things, right? Jake: It's weird. Jake: It's weird. Jake: It's weird. Jake: It's weird. Jake: It's weird. Jake: It's weird. Jake: It's weird. Jake: It's weird. Jake: It's weird. Jake: It's weird. Jake: It's weird. Surma: Now that you say that, I don't even know what that looks like on mobile. Jake: Oh, that's a good point. Jake: I have no idea either, because no one uses it, because it's shite. Jake: Okay, but when it's a single select, it kind of renders like a dropdown. Jake: And the advantage of the way it works, it's very declarative, Surma: Yeah, infamously on iOS, you get one of the, that's still like one of them, like more skeuomorphic Jake: is the user agent can render it however it wants, Jake: and it tends to be rendered in a way that fits in with the operating system Jake: and with the device. Jake: Do they still do that? Surma: leftovers where it's almost like on little wheel drums where you select the number or Surma: the option that you want. Surma: I don't quote me on it, but I think so. Jake: That's interesting. Jake: And on Android, it does show as a kind of full screen-ish overlay, right? Jake: But even on desktop, it looks like part of the OS, Jake: and the popover thing can escape the iframe it's in. Jake: It can even escape the browser window it's in. Jake: Like, it's got these kind of superpowers by being sort of Jake: an operating system level kind of thing. Surma: Yeah. Surma: And the fact that it is looking like the operating system is actually what people often Surma: dislike because they have, you know, a whole design system that somebody painstakingly Surma: designed and implemented. Surma: And then somebody wants to select and they're like, well, can't do anything about that. Jake: Do you want an ancient fact? Surma: Oh yeah. Jake: I feel like this should be a recurring segment. Surma: Grandpa Jake tells war stories from Brazzer land. Jake: Yeah, let's go with that. Jake: Welcome to Grandpa Jake tells stories from Browserland. Jake: Excellent, cool. Jake: In Internet Explorer 6 and earlier, select elements were rendered Jake: by the operating system, not by the browser engine, Jake: and it was a separate rendering pass, right? Jake: Meaning select elements were on top of everything else, Jake: like the z-index was. Surma: Lovely. Surma: Oh, it's like the rock, paper, scissors. Jake: The only thing that could render on top of a select were these other things Jake: that kind of had this same second pass logic, Jake: one of which was an iframe. Jake: Or rather, the bits of the iframe that intersected with the select, Jake: like the select wouldn't render there. Jake: But IE6 did have a code path to allow things to render Jake: on top of iframes. Jake: It was kind of like that logic was just missing from select, Jake: but it was there for iframe. Surma: Of rendering order. Jake: Well, here's the thing. Jake: So if you wanted to render a div on top of a select, Jake: like you were creating an overlay or a popup or something like that, Jake: what you would do is put an empty iframe behind the div Jake: to prevent the rendering of the select underneath. Surma: That's brilliant. Surma: I love that so much. Jake: That was another episode of Grandpa Jake's Ancient Browser Stuff. Jake: I can't remember what we were calling it. Surma: That is genuinely amazing. Surma: I love that. Jake: So that's select in general. Jake: The bad part is you can't control the styling Jake: because they're rendering differently everywhere, Jake: so how even would you? Jake: So if you wanted a dropdown that looked slightly different, Jake: you were creating your own from scratch. Jake: Even if you just wanted an image inside the options, Jake: like a flag for language select or whatever, some kind of icon, Jake: no, you were creating from scratch, Jake: and that included all of the accessibility stuff, Jake: which is really, really hard, Jake: and keyboard interaction is really hard. Surma: Well, no, you just don't do the accessibility. Surma: The accessibility stuff that we have seen and all the components people have written Surma: that do custom selects, isn't it? Jake: Exactly. Surma: It's like instantly a world of awful because suddenly you are in get bounding, climbing Jake: Exactly. Surma: rack territory, absolute positioning, Z index fighting, and all that jazz just to get something Surma: that really, you know, I just wanted an icon next to my dropdown option. Jake: Yeah, and you're right. No one gets it right. Jake: So the Open UI group, they set out to solve this, Jake: that they're going to create a select element Jake: that had all of the accessibility and interactions built in Jake: and allowed for the full and predictable styling. Jake: And it's taken years, but we are nearly there. Jake: Can't rush art. Jake: Can't rush browser standards, that's for sure. Jake: So people who might have looked at this effort Jake: over the decade or whatever, Jake: they might have seen that it was going to be proposed Jake: as a new element, like custom select. Jake: I can't remember what it was, but that's dead. Jake: That's dead now. Surma: Oh, but it also means that they have to kind of like shoehorn all the, like, you know, Jake: The new plan is to enhance the existing select elements, Jake: and this is great because it means Jake: these new fancy custom-style select things, Jake: they fall back to regular select. Surma: the all knobs and levers onto the existing syntax because it needs to gracefully degrade Surma: slash progressively enhance for sure. Jake: Yes, so it means your rich content and your options Jake: will just fall down to text content, Jake: which you have to be careful with. Jake: But I do think it's actually one of the impressive things Jake: about this effort is how they've managed to thread the needle. Surma: It's very impressive. Jake: Like, yeah, they've looked at what browsers will accept Jake: but ignore inside select and option elements Jake: and made it work. Jake: Yeah, I think it's good. Jake: So you need an opt-in, right? Jake: Because you need a way to switch it from a normal select element Jake: into this whole new world. Jake: Yeah. Jake: You know what? Jake: We're going to talk more about these little opt-in switches. Jake: I feel like they are multiplying on the platform. Jake: Yeah, I'm going to cover a few of them just in this episode. Jake: So if we think about a select, Jake: it's kind of two top-level parts, right? Jake: There's a button, and that's the bit on the page Jake: that displays the currently selected option. Jake: But it's just a button, right? Jake: It doesn't look like an HTML button, Jake: but it's a thing you focus and a thing you press. Jake: It's a button. Jake: If you give that, via the select element in CSS, Jake: appearance-base-select, Jake: then it changes the mode Jake: and falls to a cross-browser version of that button Jake: that is, like, agreed styling. Surma: Is this the first occurrence of appearance or did we have that somewhere else before? Jake: Appearance is there already, but don't ask me what it does. Jake: It's one of those ones that has always been a bit of an enigma to me Jake: because, yeah, there's, like, appearance-non, and it... Jake: I don't know. It does something. Jake: I think it might be something that kind of appeared in ancient days, Jake: and it's sort of in a standard noun. Jake: Do you know what? Surma: Wait to double check. Surma: Is this an attribute or a CSS property? Jake: CSS property. Jake: So you can apply it to all your selects. Jake: So, yeah, once you put that CSS on there, Jake: you get this, like, cross-user-agent, cross-device button. Jake: That kind of looks like a very basic dropdown-select button Jake: that we all know and love. Jake: You know, it's got the little arrow. Jake: It's got the selected item in it. Surma: I instantly wish that they would have just called it base because I would love to just Surma: do in my style sheet star appearance base that all UI controls will use that base appearance Surma: if once we have it for every UI element. Jake: And your intent there is exactly why they haven't done that. Jake: So if they said, like, right, Jake: star-appearance-base means reset all of the form controls, Jake: they're not going to ship that Jake: for all of the form controls straight away. Jake: So they're going to ship that with select, like, or whatever. Jake: But then that style is out there, Jake: and then when browsers come to do that for date picker Jake: or, you know, colour picker or whatever or some other control, Jake: they're going to ship, and your page is going to change Jake: and probably going to change in ways you don't want. Jake: So it prevents a sort of future compact problem. Surma: As long as they ship something like that, once every form element has a cross browser Jake: I guess, whether that will ever happen or not, Surma: standardized look, all new formalins should now have a cross. Jake: because you can always add new form elements in the future, Jake: but I guess if they've done... Jake: Yeah, if they do that for all new form elements as well. Surma: Like I think I think that's really nice that now there is basically the signal like we Surma: are going to give every standardized interaction element a cross browser agreed look. Surma: So you move away from it looks correct for the operating system because I think the benefit Jake: Yeah, I agree. Surma: of that was never really as big as maybe originally hoped. Surma: I could see, you know, like in a world with, you know, installable web apps, there was Surma: an element of it's nice that it looks like a native counterpart, but actually almost Surma: all apps decide their own button design. Surma: So I think, yeah, this is the better direction, in my opinion. Jake: The other part of the select is the popover, Jake: like the thing that appears when you press the button Jake: and goes away when you select an option Jake: or press escape or whatever. Jake: So you need to opt into the standard rendering of that separately. Jake: And that is done via a pseudo element hanging off the select, Jake: which is colon, colon, picker, Jake: and then in open brackets, or within brackets, select. Jake: So it's kind of like a pseudo element function kind of thing. Surma: That was bad. Jake: And again, this is for the same reason for, you know, Jake: they don't want people saying, like, all pickers, Jake: I want all pickers to be base style. Jake: Like, they want to force you to be saying, Jake: I want this to happen for select. Surma: Right. Jake: Yeah, and again, you do appearance base select on that. Jake: The nice thing about it being split is you can Jake: just opt into controlling the button Jake: and stick with the operating system picker. Jake: You cannot do it the other way around. Jake: You can't just opt into the picker without opting into the button. Surma: That kinda makes sense, I suppose. Jake: I guess it comes down to, like, you know, Jake: if you're just controlling the picker, I don't know. Jake: I don't know. They probably have some good reasons for it. Jake: But yeah, fair enough. I'm fine with that. Jake: So let's talk about popover. Surma: I was gonna ask, don't we have a popover element Surma: that recently got designed or something, or am I making stuff up? Jake: You are not making stuff up. It's a popover attribute. Surma: Nope. Surma: Uggghhh. Jake: And so, like, almost every element can now have a popover attribute. Jake: I think it maybe is actually all elements, but, you know, Jake: it only really matters on elements that render. Jake: And that means it can be shown as a popover Jake: by calling .showPopover. Jake: That means it appears on top of everything else. Jake: And that uses another feature of the web platform Jake: called the top layer, Jake: which I think was originally created Jake: to support full-screen elements, Jake: but it's since used by dialogue elements Jake: when they're in modal mode. Surma: Right. Jake: We use it for view transitions, Jake: and popovers appear there as well. Jake: There's probably some other features too. Jake: They come with, like, focus logic Jake: to control focus in expected ways. Jake: You can use escape to close them, Jake: and it returns focus. It's pretty smart. Surma: And you have this anchor positioning as well to position the popover adjacent to a specific Surma: corner of another element or something? Jake: Yes. So the popover bit... Jake: So I should say there's also, on a button element, Jake: you can add a popover target, Jake: which means, like, clicking the button Jake: will toggle or show or hide. Jake: You can control that as well. Jake: Like, that will control the popover. Jake: And that will also create an accessibility link Jake: between the button and the popover. Surma: That's nice. Jake: There's a great article by Hidde de Vries Surma: Very good. Jake: and Scott O'Hara, which covers all of the accessibility stuff Jake: under the hood here, which I'll link to Jake: because it's really good. Jake: So those features are available cross-browser, Jake: like, today. Jake: But you just mentioned anchoring, Jake: which, yes, like, Jake: you want the popover to be linked to the button, Jake: typically, but which side of the button? Jake: Well, that's kind of down to you. Jake: And maybe you want it to, like, Jake: appear on the side that has the most space Jake: or, like, favor one side, Jake: but if it would go out of view, flip it to another side. Jake: And yes, CSS anchor positioning Jake: gives you that capability. Jake: Only in Chrome right now, but it is in stable. Jake: And you can use that on any element. Jake: That's the nice thing. Jake: So the popover stuff, the anchoring, Jake: these are features that you don't... Jake: They don't have to have anything to do with select, Jake: but it is the things that select uses internally Jake: with sensible defaults, Jake: and you can modify them Jake: and use them separately. Surma: Yeah, that's really really nice, really nice layering. Jake: So any elements that you put Jake: inside the select, Jake: they end up in the popover. Jake: Well, not just options. Surma: That makes sense. Jake: It means you can use divs as well Jake: to help with layout or whatever. Surma: So in this opt-in world is then the popover just like basically an element and I can use Surma: you know relative positioning, absolute positioning, all that jazz? Jake: It will always be in the top layer, Jake: so giving it relative positioning Jake: isn't going to get you anything, Jake: because everything is sort of... Jake: Yes, you can. Absolutely. Surma: What if I wanted to arrange my select options in a circle? Jake: And you're whatever kind of layout you want, Jake: you can do there. Jake: So there is a downside to this, Jake: and, like, you get all of that CSS control, Jake: you get to do what you want with it, Jake: but because it's just in the top layer, Jake: and because you have that control, Jake: it can't escape the iframe it's in, Jake: and it can't escape the browser window, Jake: because that would be a security issue, Jake: rendering stuff in another origin, Jake: or you're rendering stuff outside of the browser. Surma: Right. Surma: I guess that makes sense and I think the feasible workaround which I assume is handled Surma: automatically that you know if the button with a popover is at the bottom end of the Surma: screen the popover will open upwards rather than downwards. Surma: So it's really only the scenario that is now problematic, it wasn't problematic before Jake: Exactly. Surma: if you have a tiny tiny iframe. Jake: Or a tiny, tiny browser window, or something like that. Jake: Yeah, and so CSS anchoring gives you that, Jake: you know, preference of positioning, Jake: all of that you control, Jake: and there are sensible defaults. Jake: Yeah, so it's a kind of minor thing, Jake: but it is a notable difference Jake: between, like, the new world Jake: and the old select implementation. Jake: Option elements still represent your options, Jake: but they can contain rich content, Jake: so images, you know, you can format the text, Jake: you can add divs to hang styles off, Jake: you can do whatever you want. Jake: There is a checked pseudo class on options, Jake: and by default that causes the before pseudo element Jake: to contain a tick. Jake: I think that might change, Jake: that's something that's currently being discussed, Surma: So again, in my circular layout, how is keyboard input handled? Jake: but again, you can override all of that. Jake: Even if that is what lands in the user agent stylesheet, Jake: you can override it to change something, Jake: you know, be whatever. Jake: It is not. Jake: Well, yes, you're absolutely right. Surma: You get up and down, I suppose, right? Jake: So you get the accessibility stuff for free, Jake: you get keyboard stuff for free, Jake: but you just get up and down. Jake: So if you have arranged your items in a circle, Jake: or in a grid, or horizontally, Jake: which a lot of the demos are doing, Jake: because it's cool and new, Jake: a lot of them don't work. Jake: Like, you would have to go with JavaScript, Jake: and when left or right is pressed, Jake: when you're on this particular option, Jake: call focus on a particular different option. Surma: I think it's fine. Surma: I think, you know, solving all of these things in one go is probably super hard. Surma: I think going so the fact that you can select any option with a keyboard, that's the most Surma: important thing. Surma: The fact that it sometimes is visually unintuitive, like I wouldn't say it doesn't work, it's Surma: just unintuitive to go up down when you visually go left and right. Jake: Yeah, that's a fair point. Jake: By default you will be able to scroll through the items, Jake: it might just not be the most expected buttons Jake: that you will press. Surma: And maybe at some point there is, you know, CSS has this whole spatial navigation thing Surma: going on, maybe that can be connected at some point, but I'm super happy that they are taking Surma: this approach for the first release of this, where you're just like, you know it works Surma: and it is a massive leap to what it was before, so, you know, it's good. Jake: Yeah, I'll link to the effort, Jake: the previous effort for spatial navigation, Jake: there's a spec written, Jake: I haven't looked at the spec, Jake: so I don't know anything about it, Jake: but I know it was done by LG folks, Jake: because of course they're on a TV, Jake: and they've got up, down, left, right on a remote, Jake: so spatial navigation is really beneficial to them. Jake: So there was spec efforts, Jake: but it hasn't really been touched in, Jake: I think, three years. Jake: So that's one of the features Jake: we haven't got out of this. Jake: Alright, that's the popover. Jake: The button. Jake: So once you've done the opt-in, Jake: there's a standard button that you can style, Jake: but you can do more. Jake: I said before that anything inside the select element Jake: appears in the popover, Surma: Oh, so that allows you to like to model the state change between is the popover open or Jake: there is one exception to that rule, Jake: and that's if you put a button element Jake: as a direct child of the select. Jake: Then it becomes the button. Jake: Like the UA rendered one is gone, Jake: and just that button you've put in Jake: is the button now. Jake: Well done. Jake: Well yes, so Jake: you can use the Jake: select open and closed Jake: pseudo classes for that, Jake: and then control your button Jake: within there to flip Jake: the arrow position, Jake: or some of the colors, or whatever state. Jake: Yeah, that's all available to you. Jake: And those open and closed pseudo classes Jake: are a relatively new thing as well. Jake: I don't know if they were created directly for Jake: select, but they've been added Jake: to select for this. Jake: I think they were also on details. Surma: So you sounded like it wasn't the intention that you can have basically one button look Surma: for open, one button look for closing. Surma: What is the intended use case behind replacing the original button with another button? Jake: Well, it's just that you can do Jake: whatever you want with it. Surma: Ah, okay. Jake: So with the previous one, Jake: it's the content that the UA comes up with, Jake: but sure, you can change the background color, Jake: the border, and all of that. Jake: But with this, you can put Jake: whatever text, images, Jake: blah, like, Jake: it's yours to do whatever Jake: you want with. Surma: Right. Surma: I mean, it's really good flexibility. Surma: How do events work in that moment? Jake: Well, you've still got the Jake: select element is there. Jake: So whether the button Jake: gets a click event, or whether that's Jake: like Jake: stop propagation, Jake: stop immediate. Surma: Because I'm thinking about, you know, in Preact, if people put their on click on one of the Jake: ... Surma: buttons rather than the surrounding selects or like only on one button and then they replace Surma: it, but then obviously the other button doesn't have a click listener. Jake: Well, you shouldn't have to add a click Jake: listener to the button. Jake: Because there's no real call to, Surma: No, but maybe you want to do something in response to a click, right? Jake: because the browser will automatically hook it up Jake: to the picker. Jake: Oh yeah, so that should work. Jake: Whether if you prevent default on the click, Jake: whether it stops the popover Jake: appearing or not, I don't know. Jake: It feels like it should. Jake: So I would expect you to get a click on the button, Jake: and then obviously it bubbles up to the select as well. Surma: I guess I was asking if I put an on click listener on the one button and then this replace Surma: mechanism kicks in. Surma: Once it's open, I would have to add another click listener to the other button. Jake: Oh, no, no, there's only one button. Jake: I think this is maybe Surma: Oh, yes. Jake: where there's a confusion. Surma: I think now I follow. Surma: So yeah, we should rewind what you were saying. Surma: Let me, let me try and see if I got this. Jake: ... Surma: If I understood it right now, you can put a button as a direct child of the select to Surma: take complete control of the look of the button. Surma: I understood that button only comes in action once the original button has been clicked. Jake: Yes, that's where we got confused. Surma: Right, so that's basically a special rule for if there is direct child button that becomes Jake: No, it's just the thing that appears on the page, Jake: the default version of that is gone, Jake: and it is now just your button. Jake: Is it? Surma: that is your signal as a developer. Jake: ... Surma: I want to take control of the select to open the button myself. Jake: Yes, exactly that. Jake: And are you ready for where Jake: things start to get really weird? Surma: Oh, yes, absolutely. Surma: The clone of the option element was like, that is actually cool. Jake: There's a new element Jake: called selected option. Jake: All one word. Jake: Well, no spaces, because it's a tag name. Jake: If you put Jake: one of those in your button element, Jake: it will receive Jake: a clone of the contents Jake: of the option element Jake: that's selected. Jake: Well, the clone of the contents Surma: Yeah, that is actually kind of clever. Jake: of the option element that's selected. Jake: Sorry, I have to do Surma: Yeah, that has a selected property set to true. Jake: some verbal gymnastics here, because Jake: it means we've got a Jake: selected option element, Jake: and a selected option element. Jake: So I'm trying to find ways to... Jake: Because there's the thing with the tag name, Jake: selected option, and then there's the thing Jake: with the tag name, option, which is selected. Jake: So... Surma: Interesting. Jake: Excuse me while I sound not entirely human Jake: while I try and make Jake: the two sound very different. Jake: It's a light DOM clone Jake: of the contents. Jake: I said in previous episodes Jake: it's a bit weird and unusual for elements Jake: to modify their own attributes Jake: in response to user interaction, Jake: but it does happen with dialogue Jake: and details. They both Jake: add and remove their open attribute. Jake: There's also the Jake: hidden attribute, if you set that to Jake: if found. Surma: Yeah, I'm surprised that there wasn't. Jake: That's an indication to the browser that if you Jake: Control-F and Jake: it thinks the content is inside Jake: that element, it will Jake: remove the hidden attribute automatically Jake: from that element. So, you know, Jake: there are cases where browsers Jake: will modify elements themselves. Jake: It's just very rare Jake: and weird. But this takes it to a whole Jake: new level because it's a whole Jake: clone in the light DOM that's sort of Jake: dumped into this other element. Surma: Maybe there were attempts and it didn't work out, but my immediate thought would have been Surma: slots. Surma: Right? Surma: Like, like in Shadow Dome, but maybe we can have slots outside Shadow Dome, because that Surma: would have also maybe made sense here? Jake: So there isn't the concept Jake: of projecting an element into two places. Jake: And that's Jake: the problem we've got here. It's because when Jake: you've selected an element and you open Jake: the select again, you're seeing Jake: that item in two places. You're seeing it in Jake: the popover and Jake: in the button. Surma: That's true. Jake: And there is the Jake: elements function in CSS, which only Jake: Firefox supports, which lets you create Jake: a bitmap copy of another Jake: element, but that means it can't Jake: be separately styled. Jake: Whereas this full clone can be Jake: independently styled. It can receive Jake: its own events. Surma: I was just gonna say, it is actually quite flexible, almost elegant, in that if an option Jake: ... Jake: ... Surma: is the selected one, you can style it separate, you can style the appearance of inside the Jake: ... Jake: ... Surma: select drop-down button thingy separately, because it is now a full clone. Jake: ... Jake: ... Jake: Exactly. But it gets funkier. Jake: The current plan, and this is under Jake: active discussion, is Jake: that if you modify Jake: the DOM of the option that's selected, Jake: it triggers the cloning steps Jake: again synchronously. Jake: So if you create a div Jake: and you put it in the Jake: option that's selected, and you give it Jake: a class name, and you give it some Jake: text, and you Jake: change the inline style, Surma: Of course, you wanna immediately argue it doesn't have to be synchronous, but I guess Jake: that's how many? One, two, Jake: three, four. That's four Jake: modifications. So that's four times Jake: the entire contents of that option Jake: is cloned and inserted Jake: into the selected option element, replacing Jake: whatever content was there. Four Jake: whole clones. Surma: for certain logic, it might have to be. Jake: Right, and that's one of the things Jake: they're discussing, that should it be debounced, Jake: but things are sort of tending towards synchronous Jake: right now. But it also means that if you're Jake: animating something in the selected Jake: option using, like, GreenSock, or Jake: Anime.js, whatever, these libraries Jake: they modify the style object Jake: every frame, which is Jake: reflected to the style attribute, Jake: which is a DOM change, which is going to trigger Jake: the cloning operation every frame. Jake: And it's not just of the element you're modifying, Jake: it's everything in the Jake: option. Surma: But animation is always performance foot gun work, like people who do this need to know Surma: what they're doing, right? Surma: Like I am firmly of the opinion to give sharp tools to developers, let them run with scissors. Jake: Well, this is the thing, and if you were Jake: animating rotation and opacity, Jake: that's two writes to the style object, Jake: which is two writes to the style attribute, Jake: so that's two DOM modifications Jake: which triggers the cloning algorithm twice Jake: per frame, and Jake: on and on it explodes, you know? Jake: So, Surma: Yes. Jake: also, if you've got a CSS animation Jake: on an element, Jake: that starts when the element Jake: is, like, mounted. Jake: Like, when it's in the document. Surma: I was gonna ask because, you know, what about, you know, old school animated GIFs or even Jake: And if this thing is being recreated Jake: a lot, people, like, using Jake: React might have experienced this, the CSS Jake: animation will appear to reset, Jake: because it's a new element. And Jake: if it's a custom element that has, Jake: that's going to perform a fetch on construction Jake: or insert, like, this is going to be happening Jake: because of the clone, it's going to be happening Jake: time and time again. Surma: you know, video tags? Jake: Oh, exactly, yeah, you'll lose, Jake: and that's the thing, if Jake: any of the state is not represented Jake: by attributes, such as a canvas, Jake: such as the video playback position, Jake: then that's going to be lost. Jake: So, yeah, Jake: have fun. I think it's okay, Jake: the cloning thing, but I Jake: think the way it clones everything Jake: on any modification Jake: synchronously, one of those things needs to Jake: change. It's not quite right. Jake: I would prefer a pattern where Jake: if you modify something in the selected Surma: Now, here's a curveball of doom. Jake: option, it should make the Jake: same change on its related clone. Surma: Remember a couple episodes ago when we were talking about VDOM in the browser? Jake: Yes. Surma: What if instead of doing a full clone and effectively overwriting the child tree, it Surma: would do a VDOM diff and actually only change the attributes and properties? Jake: Yeah, that's a big Jake: curveball. I just think it would be simpler to say, Jake: like, it knows when it's cloned everything, Jake: and it can map, you know, Jake: the contents of the option to its clones. Jake: So if you edit an attribute Jake: in the selected option, Jake: it just sets the Jake: same attribute, the same name on the clone. Surma: So like basically replace the actions that are being done in one element to the other Surma: element, which is kind of, it's kind of what I was saying. Surma: It's just like, I saw the bridge to like, you know, VDOM diffing, which is the same Surma: effect, just more complicated, but yeah, true, yes. Jake: We've done this in Shopify, right? Jake: This is how Shopify extensions work. Jake: Something happens in the... Jake: We've got a virtual DOM in a worker. Jake: It's not a virtual DOM in the React sense. Jake: It feels like a real DOM, but when Jake: you do stuff in there, it's replaying the actions Jake: somewhere else, like Jake: through a security layer. Jake: I think that's what should happen. Surma: And maybe it will, I suppose in terms of, you know, with my very basic specking head Surma: on, a shallow or a deep clone is much easier to spec right now when they're already trying Jake: No. Surma: to spec all the other stuff, then also inventing, because that's not a thing anywhere on the Surma: platform, right? Jake: No. I mean, this whole Jake: cloning thing is new anyway. I mean, Jake: cloning isn't new, but doing that on Jake: user interaction is new. Jake: But yes, there is an existing algorithm Jake: for cloning elements, so Jake: they're leaning really heavily on that. So it would Surma: Maybe it's a step to, you know, maybe it's something they do, let's post MVP kind of Jake: be a lot more spec work to do the, you know, Jake: synchronizing the two trees, Jake: but it's not a lot. Like, as I've written Jake: it before, it's not... Jake: It's okay. It's more than what they've Jake: got currently, but I think it would remove Jake: a foot gun. Maybe. Surma: thing. Surma: I would understand if, if they did that, but. Jake: But I would say the good news Jake: is this is entirely opt-in. Jake: Using this selected option thing, Jake: you could say, well, I'm using Jake: React, so I'm just going to listen for Jake: the onChange event on the select, Jake: and I'm going to update the contents of my button. Jake: You know, and in Jake: that case, you're not limited to Jake: the DOM structure of the Jake: option. You can do whatever Jake: you want, and it's fine. Jake: So, Jake: and I think that's probably what I would do Jake: if I was using a framework already, but Surma: Yeah, and it's really nice that they have a pattern where it's opt-in, like you can Jake: whatever. It's nice that there Jake: is a non-JavaScript version there. Surma: choose to do the selected option tag, or if you just don't have it, then none of this Surma: is a problem because you either don't want the select option to be shown, which would Jake: Exactly. Surma: be a bit odd, or you're taking matters into your own hands. Jake: But that's not all, Jake: right? Let's say you want Jake: your fancy new select to animate. Jake: So, a basic thing for it to do would Jake: be to animate from height zero to Jake: its full height. Jake: You could do this as a clip path, but let's say we're Jake: just going to animate the height so the Jake: box shadows and the borders do the Jake: right thing, whatever, and we'll, you know, Jake: optimize the layout so it's not too bad. Jake: You could slap a CSS animation Jake: on the popover element. Jake: CSS animations run when an element appears, Surma: Wait, with CS animations, if I just say just the only keyframe I specify is from, oh, interesting. Jake: so you could do that. Jake: But you can't animate to an intrinsic Jake: size in CSS. Jake: Like, you can't animate to height auto. Jake: You can't animate to height Jake: minContent or fitContent or Jake: maxContent. Jake: It doesn't work. Surma: I did not know that. Jake: Yeah, it needs to be a number Jake: at the other end for it to work. Jake: Except now you can, Jake: and there is an opt-in, another opt-in. Jake: Are you ready? In CSS, Surma: Wait, is that the CSS function or property or? Jake: if you do interpolate-size Jake: colon Jake: allow-keywords, Jake: ding ding, that's it. Jake: And this one Jake: inherits, so you can just put it on root Jake: and be done with it. Jake: Now it just works. Jake: There's also Jake: calcSize, Jake: which you can say, like, Jake: yes, sorry, it is a CSS function. Jake: You're right. And it means you can say, Surma: Ah. Jake: like, give me autoHeight divided by Jake: 2, or multiplied by 2, or Jake: minContent. Surma: That is lovely. Surma: Oh, that's going to be very useful in so many places. Jake: Yes. So there's sort of two ways to do Jake: the same thing. Like a simple way, Jake: and then a way that lets you do Jake: maths. Surma: That then together with clamp and all those shenanigans, is it always in reference to Surma: the element that it's being used on, or could I even do calc size on like from another element Jake: It's the same element, Surma: and use the result? Surma: Nah, that's fine. Jake: unfortunately. Surma: That makes sense. Surma: I guess otherwise you have the same problem as they did with resize observer, you could Jake: Yeah. You might be able to, Surma: have circular layout dependencies. Surma: Oh, that's fine. Jake: I guess you could do it relative to a parent Surma: That makes sense. Surma: I guess otherwise you have the same problem as they did with resize observer, you could Jake: by the parent setting a custom property, Surma: Jake: but... Jake: Yeah, that's always the problem, isn't it? Jake: This isn't a select feature, again. Like, you can use this everywhere. Jake: It's Chrome only right now, but it'll Jake: come to other browsers next year, I guess, Jake: maybe, hopefully. Jake: Who knows? Oh, okay, so Jake: what about the opposite side of the animation? Jake: So, animating out. Surma: Well, it's like you said, when a new element appears in the DOM, it's CS animation start Jake: And this is always the harder one, Jake: because, Jake: yeah, because of displaying none, Jake: and it being removed from the top layer Jake: immediately. Surma: playing. Surma: And so you can just basically put a fade in animation on an element. Surma: And once attached to the DOM, you know, animation will play. Surma: You can set it. Surma: It's a repeat to one. Surma: You can listen to the transition or animation and events and just go about your life. Jake: Exactly. Surma: But when you remove a DOM element from the tree, it's gone. Surma: There's no way to intercept that and keep it on screen to fade it out or anything like Surma: that. Jake: There's a solution for it as well. Jake: I mean, one way is view transitions, Jake: but if you're just Jake: making something display none and removing Jake: it from the top layer, there's another way of handling it. Jake: You can set a CSS animation Jake: or transition on the display property, Jake: which delays Surma: Wait, I thought discrete values could already transition, they just flip at 50%. Jake: it applying Jake: if you're animating out. Jake: So, Jake: you need to opt into this. Jake: It just works with animations, Jake: but with transitions, you need to use Jake: transition-behavior Jake: allow-discrete, Jake: which allows discrete values to transition. Jake: It's on all discrete values, but... Jake: No, that's how it works with animations. Surma: Oh. Jake: They don't work with transitions Jake: until you flip this bit, Surma: Flip a bit. Jake: and then it's fine. Jake: But when something is transitioning Jake: to display none, it converts Jake: to display none at the very end, Jake: but it becomes inert during Jake: the whole period. Surma: Very good. Jake: So that means that screen readers, Jake: keyboard, mouse, it's gone. Jake: It avoids the accessibility Jake: issues, and it means you can't Jake: double-click on a button inside that thing Jake: that you've told to go away. Jake: This is probably the last feature Jake: I got in to Web Standards Surma: I mean, that's a really good improvement. Jake: before I left Google. I had to get Jake: testimony from a bunch of framework Jake: developers to say that this is important Jake: and this would be a Jake: foot gun if it's not done. Jake: So that is one of the features Jake: that has landed. Surma: The only thing I wish there was that there's some way to say, like, if a DOM element gets Surma: removed, remove it from the JavaScript facing API, but keep it around until the animation Surma: is done. Surma: Especially if a framework just removes an element, then the just just to see as animation Jake: You're pretending like I never created Jake: view transitions, Sama, actually? Surma: can play. Jake: But that was Surma: But those are just for transitioning views, isn't it? Jake: one of the problems we aimed to solve there. Jake: It's like, how can you animate the thing Jake: that isn't there anymore? Jake: The solution to that was to use Jake: screenshots of the old thing. Surma: Here's my confession. Surma: I have not used view transitions. Jake: Mate. Surma: I've not written any. Jake: Mate. Jake: Cut steep. Surma: I think I think I think you're breaking up with me. Jake: I think I am. Jake: No, I Jake: forgive you. I think Jake: my confession is now that we've got Jake: cross-document view Jake: transitions, I kept meaning to add them to Jake: my blog and stuff, and I just Jake: haven't found the time. Jake: Whatever. Jake: Okay. Back to the problem. Jake: We haven't solved the full problem, because we've still Surma: Wait, did I get the problem right? Jake: got that issue of it disappearing off the top layer. Jake: So, the solution to that Jake: is to set a transition on this Jake: new CSS property called Jake: overlay, and that Jake: is a way of kind of delaying Jake: it disappearing from the Jake: top layer. It kind of pretends Jake: like overlay has a value Jake: of top layer, but you're not allowed to set this yourself. Surma: The ring is like when I'm closing my custom select, it just poofs goes away. Surma: And we obviously want to have an opportunity to make it smoothly go away to the developers Jake: So, Jake: you need to keep Surma: liking. Jake: display around Jake: for longer, but you also need to keep it Jake: in the top layer for longer. This problem Jake: also exists with the dialog Jake: element. So, yes, it's kind of pretend Jake: property that lets you Jake: set something into the top layer, except you're not Jake: allowed to set it in the top layer, but Jake: you can put it in a transition which Jake: keeps this user agent set value Jake: top layer Jake: around for a bit longer. Jake: It's a bit hacky, Surma: Ah, it feels odd, but I guess it solves the problem. Jake: but it does work. Surma: But it's limited to things in the topic. Surma: I can't just use the same thing on elements anywhere else on the page. Jake: So, with this display property, Jake: you can use that on any element. Jake: Yeah, that works on anything, and it's in Chrome and Jake: Safari now. But this Jake: extra one that does the top layer Jake: thing, that's Chrome only Jake: right now. And yes, that's only really useful Jake: for Jake: this select element thing. Jake: It's useful for popovers, and it's useful for Surma: Right. Jake: dialog. Surma: OK, that makes sense. Jake: Final bit. I sort of Jake: described it as like we're doing an animation in, Jake: but we're having to use transition Jake: to make something transition out. Jake: And the reason for that is because Jake: if you want something to animate just when it appears, Jake: that's not a transition because it's in that Surma: Mm hmm. Jake: state already, whereas animations do let Jake: you do that. Something appears, do your animation. Jake: But they've also added a way to make this work Jake: for CSS transitions. And that's Jake: of benefit because it means that Jake: if the transition in is interrupted, Jake: it can skip Surma: Mm hmm. Jake: some of the transition out. It can start Jake: it halfway through or whatever to make Jake: a smooth transition. That's one of the Surma: Mm hmm. Jake: nice benefits of CSS transitions. Jake: So they added Jake: at starting style, which is a block Jake: which lets you, Jake: for a selector, Jake: say, pretend Jake: that it had these styles Surma: Mm hmm. Jake: before it was created. Jake: And so if that has Jake: a transition applied to it, Surma: Yeah. Jake: when the thing appears, it's going to transition from those Jake: starting styles to its actual styles. Surma: I feel like I love the problem. Jake: ... Jake: ... Surma: I love that they made a solution. I'm not sure I love this specific solution syntactically. Jake: ... Jake: ... Surma: But, you know what? In the end, like, I don't have a better solution at hand. Jake: ... Jake: ... Surma: So, and again, I can use this on any element, right? Like, I can define a Jake: ... Jake: ... Surma: transition now that plays when I add an element to the tree. Jake: ... Jake: ... Surma: Not just an animation. That's really cool. Jake: Yeah, I agree that Jake: so much new syntax is being chucked Jake: at CSS. It's kind of growing Jake: faster syntactically than Jake: JavaScript, it feels like. Surma: Mm hmm. Jake: Yeah, and it's difficult to keep up with. Jake: But yeah, it's a solution to the problem. Jake: And yeah, you can use it everywhere, but it is Jake: useful for select. Jake: So that's it, really. Jake: We're almost in a position to create these Jake: custom select things. People should play with it Jake: and give feedback. Surma: Yeah, I'm genuinely quite excited to look at some, I'm sure you will have Jake: ... Jake: ... Surma: some demos to link to that I can look at in Chrome Canary or something. Jake: ... Jake: Yes, I'll link to all of that. Surma: Because I want to dig into that code and get a bit familiar with all Jake: ... Jake: ... Surma: the individual primitives. Because what I do think is really, really nice that they didn't Jake: ... Jake: ... Surma: just, here is a stylable select. But they were like, what is Jake: ... Jake: ... Surma: missing across the platform that we can then compose to Jake: ... Jake: ... Surma: yield a stylable select element. And yeah, that deserves applause. Jake: ... Jake: ... Surma: That's really cool that they went about it this way. Jake: Exactly, yeah. It's ten general features, Jake: right? We've got popovers, buttons that Jake: can activate Jake: popovers, and they're also Jake: working on general activation, Jake: like general declarative, Jake: you know, click this button, it makes this other thing do a thing, Surma: Thank you. Jake: whatever. CSS anchor Jake: positioning, the open and close pseudo-elements, Jake: transitioning, animating Jake: to keyword sizes, like height-auto, Jake: calculations involving Jake: those keyword sizes, Jake: transitioning to discrete values, Jake: like display-none, Jake: that kind of thing, animating Jake: display with auto-inert, animating the Jake: overlay for the top-layer thing, Jake: and the starting style. That's ten features Jake: that are kind of all part of Jake: making custom selects work, Jake: but you can use them elsewhere. Surma: It's a pretty big flex for standards land. Jake: ... Jake: ... Yeah. Jake: It feels like the right way, right? Jake: Rather than just, as you said, Jake: creating a general select thing that has Jake: all of this magic in it, it's like, no. Jake: Most of the magic can be explained by Jake: other features. Surma: Yeah, no, that's brilliant. That's really good. Jake: ... Jake: That's all I've got. That's it. Jake: That's it. That's the content. Surma: I mean, you say like that wasn't a lot. I feel like you have explained ten features. Jake: ... Jake: ... Surma: So I'm gonna, I'm gonna have to sit down and digest. Jake: ... Jake: Well, there you go. Oh, thanks, mate. Jake: Yeah. Shall we all have a Jake: lie down? Surma: Yeah, let's let's have a lie down. Jake: All right, then. Jake: Okay. Well, there's nothing Jake: else to say other than Jake: happy next time. Bye! Surma: Happy next time. Jake: ... Jake: ... Jake: ... Jake: ... Jake: ... Jake: ...