 Welcome to another episode of GUI Challenges, where I build interfaces my way, and then I challenge you to do your way. Because with our creative minds combined, we will find multiple ways to solve these interfaces and expand the diversity of our skills. And in today's GUI Challenge, we're building a switch group. And that's not a button group. This looks like a button group, but if it's a button group, each of these could be highlighted in blue. But notice how as one is enabled, it disables all the other ones. This is a switch group. Only one of these can be active at a time. I mean, makes sense, right? It can't be left aligned text and right aligned text at the same time. So I'm excited to break this down for you. I got some great HTML to show you and some cool CSS tricks. Let's get started. Here we are in the debugging corner looking at iPads. We have Safari all along the top here looking great and all the different browsers in Enlightened Dark, which is nice that this particular component is, you know, savvy to that. I always like doing that, right? It's really fun. We have Android down here. So we have Chrome in these two panels and we have Firefox down here. And everybody is happy with this particular layout. It's just using a radio group essentially as the kind of foundation in the HTML here. And then a couple of tricks like with grid and has to kind of help us represent the state of those particular radio buttons and group them in a nice way. And anyway, we'll get into all that. But here's the light and dark across all these different browsers just to show you. It's looking great. Well, now let's go look in Chrome and we're going to kind of build this up from the ground up. I wanted you to see how the HTML looks and then see it kind of progress over time into this really nice set of buttons. So let's go check it out. Here is our unstyled HTML. It's just the interactive document portions. So we've got a field set as our first element. That's what's wrapping everything. And then you see how that line kind of goes right into this little header element. That little header element is called a legend, which has like one of the coolest HTML element names ever, like, oh, I'm a legend. That would be super cool to say if I was an item in the DOM, right? Uh, no, that's definitely a nerdy joke. And then look at, we have a class here. It's called switch group. It also has an ID. This is so the JavaScript can listen to the field set for changes. I don't have to listen to each one of these input type of radios for changes. I can just listen to the field set. And I love doing that. It's super cool. So then we've got this group switch and inside is an input. It's this one is currently checked. It's a type of radio. Its name is text alignment. And that's what's going to group it with the others here. You can see they all have the same name. They each have a unique ID and they have a value left, center, right, or justify. And of course, a label. Don't forget your labels. And that goes with that ID. So that ID of text left has this clear label of a text left. That makes the label interactive as well as the input. So look over here, I can hover over the label and click the label itself. This is really handy for mouse users, keyboard users, screen readers. Everybody likes the way that labels and inputs work together. They'll always include those together. And in my particular case here, I made my labels a little verbose. So look, it says text align left, even though it's in a group called text alignment. So a screen reader could definitely derive that they're inside of a group and that the value is left inside of text alignment. But when I'm using the screen reader, I kind of find it nice to hear it again. It's not annoying at all. In fact, let's test the screen reader. So here I'm going to hit command of five. Voice over on Chrome Canary, switch group vertical line GUI challenges, part of the group GUI challenges, Google Chrome Canary, Adam, Winto, text align left. There's a couple of ways to move around. The first one that you're going to be tempted to do is use the arrow keys and the arrow keys work awesome. They'll deselect where you previously were. Oh, hey, let me tab in. Text align left, selected radio button, text align center, selected radio button, two or four. They'll deselect where you previously were, excellent, and they will select the item that you went to. Text align, text align right, selected radio button, three or four. As if we were clicking through these ones. So here I'll go through all these. Text align justify, selected radio button, four or four. You can see the value is changing. So when the arrows move over to this element, it's becoming selected. It's sending an event and we can see it changing the alignment here. Now screen readers have another kind of special feature, which is what they, at least on Mac OS here, you can hit control and option and kind of use your virtual cursor, text, text align center, radio button, two and, and pseudo move to these other other elements. And then when you're ready, you can hit control, option space and actually select them selected. Great. So now we know we have a strong baseline, a set of functionality here. We have a field set. We have elements inside of there that are grouped and named and have relationships. Mouse user is able to use it. A screen reader user is able to use it. Keyboard users can use it. Let me just get rid of our screen reader here, command F5. And I can tap through our interface. Now I'm just using the keyboard. So it's no longer a screen reader specific experience. This one's just a keyboard. So we don't want to, we don't want to break this. We want to make sure that this stays strong as we move this into something more visually pleasing for mouse users and sighted users. So knowing that this is our strong baseline, let's not disrupt this strong set of base user experience and move forward. Let's go ahead and bring in some of these extra elements here. So I've got a tooltip and some SVG is bringing the tooltips and the SVG. So remember, these are extra. The tooltip is totally extra. The SVG is just decorative. They're not bringing anything to the experience here other than sort of visual affordances and niceties, which is nice where we have a very sturdy foundation. All right, week I have seen and understood our HTML. This is it. We're looking at what we are going to start styling and let's just jump right into the style. So the first thing that we're going to do is we want to make this switch group an inline layout. And I'm going to do that with a quick little flex layout. Right. So by default, it's going to make columns. We see columns here and we can give them a little bit of a gap between them. And it's a very small gap. And we'll see why that gap is small soon. We're also going to set the max inline size or the maximum width to the maximum of its content. And look, we have four items here. And now we could see it kind of shrink wrap to fit there, which is really nice. It's also defensive against flex and grid stretching. So since it's a child or all these elements or a child of a grid or flex or maybe this even this field set is a child of a grid or flex. Setting that max inline size, make sure it's not going to grow and then become kind of too wide for all the items it needs to host. Okay, the next thing we're going to do is make it look kind of like a card. We're going to make it look like a card by setting the background to surface one. This is a variable inside of the open props normalize. This is adaptive. It will change based on light or dark. We have some padding again, very small because we're making a kind of small icon toolbar when we have a border radius. It's a small border radius and we have a small box shadow. And the next thing we're going to do is we're going to remove that border that comes with a field set. It looked cool over the legend, but we don't need it in the way that we're going to make this sort of floating action toolbar here. Okay, we get border none. Great. We have an animate box shadow. So what we're going to do is when we do change box shadow on hover and focus within, we're going to make sure that that box shadow kind of bounces a little bit with this little bit of this ease squish three from open props. And we'll check that out in a second. The next time I'm going to skip down to here where we have the icon. Let's bring the icon color in to current color. Excellent. Okay, so this is saying in our selector, we were using some nesting here, our group switch, carry that selector in. So it's dot group, switch, space, direct descendant, selector, SVG. Find all the SVG and make them the current color, the current text color, which is nice because the current text color is also adaptive to light and dark. So as the theme changes, so will our icon color. Excellent. Okay, our next thing here, and here we're jumping into some more nesting. We're going to change the box shadow when there's focus inside. So cool. Let's bring in that little bit of an animation here. And this is saying when the switch group has focus within inside of it, or is being hovered, increase the box shadow to shadow four. And there it is. You can see box shadow four, it has a little bit of a bounce. And so putting the bounce on the shadow kind of makes the element looks like it's bouncing as it's lifted. Okay, and then this last thing here, we are going to select the legend and we're going to hide it. We're going to keep it in the DOM. We're not setting display none because it is providing valuable information to screen reader users, but we just don't want it visible. So we're going to make it visibility hidden and we're going to set its block size like its height to zero. So now it's consuming no space and you can't see it, but it's still in the document and we're done with that first part. So let's look at the group switch. This is each icon button itself. What we need to do is we need to stack the radio and the label and the icon all together into one square. And then we want to make sure that that label text is still interactive because that's going to give us that big nice large kind of like hit area, that interactive area that's going to then trigger the different things. So look right now, if I click on the icon, I don't activate it. If I click on the label, though, I do. So we're going to make that label cover this whole space. It's going to be really cool. And we're going to do that with display grid. So display grid is going to set a single cell grid and it's going to prepare for a pile. I call them a pile because we use the word stack so often. And stack usually means like a vertical stack, like these are stacked now. But I want a pile and to make the pile, we're going to have to target each one of those children and tell them to share some space. Let's see, where is that pile code? Let's see, mm-hmm, looking at these checked. Aha, right here. So all direct children pile into a single cell grid, that's what we want. And we're doing that by selecting all of the input labels in SVG children. So not the tool tip that is here as a child of these particular buttons. And I'll hit save and there is our pile. Look at our radio button as humongous, our icon is big and our label here. And these are probably select, no, they're not changing. So if I click them, look, they're not changing. So something is front of the other one. I bet the SVG is sitting in front of these and making them non-interactive. So we'll get to that. Okay, let's set a width because these are obviously too large. We're going to set the inline size to size seven. So this is just a size that comes from OpenProps. Look at that, we're getting some collisions already. So we're going to have to, we'll figure it out here in a second. We're going to round out the corners, let's round out the corners. And the reason that I'm doing a little bit of math here is so that the nested radius looks kind of weird if it's the same radius, but it has like a different size. Anyway, there's a code pen here. I'll put it on the show notes for you to check it out. You can go see how that works. Okay, so if this is where we did the pile, let's fix the interactivity here. So we're saying if it's an input and a label, we want the opacity to be zero. We want the overflow hidden and we want the white space no wrap. So that's taking our text label, making sure that it's not kind of consuming a bunch of vertical space. We're setting the overflow to hidden so that it's appropriately fitting it inside of the cell that we're trying to fit it inside of. And we're setting the opacity to zero. This is crucial because now it will still be interactive. So if I click, see, we can actually see changes in our UI because our values are being received. We're just not seeing selected state yet, so we still need to represent that. All right, it's cool, getting some good progress here. Let's update this. So this is saying if the motion is okay for this user, which this particular open props value here refers to prefers reduced motion, no preference. That means motion is okay. This user doesn't have a preference. So we're going to give them the full motion experience. And that's going to include an outline offset animation and a background color animation. Can we see that yet? I don't think so because nothing's really selected yet. So we'll see that in a second. So now we're going to target all of the, let's see, any of these elements that are not active, give them an outline offset. So that's going to give them a sort of bouncy active state. We'll see that in a second. So here, let's set that active state. So if it has focus visible and focus within, so if they are using a keyboard, so here I'm going to focus in here and hit spacebar. So focus visible says we only want to see this focus ring if someone's coming from some technology where they want to see focus visible. And if they are in that sort of technology and there's focus within, well then we want to see represented here. So I can move between these and hit spacebar to sort of activate them. And we can see that that outline is animating based on the motion preferences and the transition that we set and the various values. Super cool. Okay, so now let's see if the button has a checked child. And that child being checked or not is going to allow us to visually represent the selected state. So if this button has a child that is checked, which is going to be that input.radio, we're going to make the color, the link color of the page, which is another adaptive prop that comes from open props. So this is going to be a dark blue and a light theme and a sort of light blue and a dark theme here. And we're going to set that to the text color and the SVG, we set the SVG to the current color. And so that's adapting to the text color that we've set for the context of the element. It's kind of cool. Let's set a button hover. So now it's going to play into those different padding and border radius amounts and look at selected state and we can see the hover color popping in here, looking cool. And notice it's surface two. So surface one was this background and surface two is just another surface. These are adaptive for light and dark and we are done. That was it. We're using the tool tip that came from a previous episode of GUI challenges on tool tips and we dropped it in. Again, they're non interactive tool tips. They're just extra information and they're there just to help mouse users understand what their values are in case they were wondering. And that is pretty much it for this GUI challenge. I hope you had fun watching this and watching me sort of take a field set with different input type radios as a group and turn them into a really nice looking switch group. I'll see y'all in the next GUI challenge and take care y'all.