 Welcome to another episode of GUI challenges, where I build interfaces my way, and then I challenge you to do it 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 morphing button. One of those kinds of buttons where like you submit a payment or you say, Hey, start crunching this image or do this AI work or whatever it is. And you hit a button, it goes into another state, it transitions to another state, and then eventually goes back to the state that was in the beginning. So we have a multi state button that needs to kind of morph and adapt to these different amount of contents that it has. It's a perfect use case for view transitions. And so that's what I used today. Can't wait to show you, let's dig into the code. So a little bit of background about view transitions, let's just assume you've never heard about them at all. This is a great starting places as an article by Jake Archibald covers all of the different things that you can do with this API called view transitions, and it was previously called shared element transitions. And what this allows you to do is tell the browser that you're about to change something on the page. So why don't you look at the state of all the elements, and then I'm going to change the page. And when my function is done, go ahead and seamlessly transition from where that element was or many elements were to where these new elements are. And I've showed a couple in the gooey snippets that how you can use this to do things like animate display none, you can animate text replace, it has so many superpowers. And so today I'm using it to apply some styles and transitions to a button. So here we have our button that doesn't have the view transition work applied. Also looks like it's well it's missing a whole bunch of styles and we'll get into that soon. But I wanted to give you a little bit of background on view transitions give you a reference to a nice resource. But let's dive into how I achieved this in this button today. So the first thing that I'm just going to show you is that I've set up a SVG element here with the style display none. And I've put a symbol inside that has all the different spinner path information and I give it in a nice name. And that becomes really handy because then I can use that with this use tag and I can just say hey use icon dot spinner. And so in my JavaScript where I'm kind of injecting new contents when you hit this button you can see that that spinner gets set up here. And that's where it's coming from. So I like the use technique for SVG. I think it makes it kind of nice. But it's up to you. So anyway, that was where the icon is coming from stuff like that. And then just here I have a lonely demo. I have a lonely button with an ID of demo. And it starts out as do some hard work. So that's the HTML that's sort of supporting this. I've got some styles in here. So first off, I'm loading in open props in the normalize. That's why I have like a dark background here right now is that you automatically get the light in the dark theme. But let's import the buttons and get a nice styled button. So now we get a nice light and dark styled button here. Kind of cool. It has a nice little clicky effect. And we have some support styles that just put this demo in the center. Probably even get rid of the gap don't need the gap. There's not more than one element in this demo. So we'll just crush that. And the next thing we're going to add is this morphing button concept. Well, let's do that in a minute. Let's look at what the JavaScript is doing. I have three states which is idle state. We can see it's right here and that do some hard work phase. In the next when it moves into sending, which has the spinner and the working text. And here we'll just click that button and see it. There it is working. And then we have the done state which, you know, looks really happy and probably could add another spinning successful check mark the animation right here if you wanted to and just need another icon. No big deal. So what happens though is when we click the button, we're going to set the state to sending, which is going to add this spinner in the working state. We set a time out. So this is just like a really cheap state machine. We set a time out for 4000 seconds or 4000 milliseconds, which is going to be four seconds anyway. It sets a new state and then eventually after six seconds sets the state back to idle. So this entire animation takes six seconds. It has four seconds of working, two seconds of done, and then it goes back to its regular state. You can kind of already see that there's a crossfade happening here. Do you see how like it crossfades between the different states? That is because we're using the API for view transitions down here and we're also doing it as an additive bonus. So while this demo currently only works in Chrome, it will eventually work in any browser that supports view transitions. But what's nice is we're only calling this view transition function and doing this morphing if the browser can do it. Otherwise it's just going to change states immediately and it's no big deal. But what I want to come back to is that by using this API at all, you get crossfades between your animations, which or between your states and I think that's really nice as a default. So that's why we're getting crossfades is I'm calling start view transition. And so then the other way that this works is just so that we break it down sort of again conceptually at a high level, view transitions in this single page application model where I'm using JavaScript to invoke them. You need to tell the browser I'm about to do some work and that way it can look at the current state of your button in this case. And then after you do some work like in this case set the inner HTML to something new, your function will complete and the browser will take another screenshot of that element and then allow you to morph between the two. So that is the extent of using the API and the rest of it kind of comes down to some CSS. So let's dig into the CSS that kind of makes that happen and we'll undo our comment here that's commenting out the morphing button styles and go look at what's happening inside of here and even take some out. Let's take out this and let's see what happens when we just give it a view transition name of by button. So again, we've got our button, we have our styles, we have our JavaScript that's going to call that function and you can see it morphing between our different states. Now there's going to be some awkward morphing happening. Look at how it's sort of like ghosted out the one of the past and it also was kind of large in a lot of ways or it's over sized and that's because the browser is really optimized for maintaining the aspect ratio of something in these transitions and that's essentially what these styles here do. They say I see you browser trying to keep the aspect ratio on this by button element but I don't want that. I'm kind of opting into a squish effect and so here let me save these styles and you can see watch this the animation happens this time and you can see some squishing happening. In fact, let's just open up the dev tools go down to animations and slow the animation down and also move this under. Yeah, here we go. So we've got a 10% animation going. We're going to really see the squishing happening there. Nice. Did you see that? We'll go back to kind of fast and another one is it squishes. So normally it's not good to squish your text. I would almost always advise against that but in this particular case where we have this morphing button, it's kind of super duper convenient for us and the effect happened so fast. I don't think there's a whole lot of you know visual loss happening there. So here let's just see this again as it goes some squishing and that's because again we're forcing the height and the width of the old image and the new image to be combined together to be squished into the space of the element as it is naturally in the DOM. So when we reference view transition old by button we're looking at the image of the old button and when we reference view transition new by button we're referencing the new image that's coming in. So the browser when it does these view transitions it's working with bitmaps it's working with like textured images and that's important to note because that's how we achieved our effect is by kind of squishing it into space and now we get a nice little morphing button. Right kind of cool and we can add as many new states in here as we want like let's go from sending to registering yes because that's probably going to happen here registering registering and then in here we'll say you're going to go from done to registering well here I think we should actually do registering first at two okay so now we should have a whole new state coming in here let's see working registering and we're done let's even make registering have a whole bunch of text registering your new thingy alright we're working yes registering your new thingy and it's done so what's especially neat here is the browser uses actual layout of the new state and then the actual layout of the old state and it's all contextual so if we were in a right to left language if we had you know translation happening here all of that stuff would still apply just as much as it would have before because the browser is very naive here and we've given very light amount of instructions about what to do so that is how I made a morphing button I really just give it a name and this is important with you transitions if you want to customize the way that the transitions happening remember by default it's just a crossfade I give it a name and then I can reference the old and the new so there's other demos where I've shared where I make the old one scale out and fade out and the new one gets to slide in there's all sorts of opportunity to handle and customize how the old one goes out and the new one comes in it's really really fun really powerful API and I love that this just sort of simply upgrades to a morphed animation whereas by default it'll just happen instantly and I don't think there's a whole lot of experience lost there the content is still there the screen readers still report all of the changes that are happening to this button which is really nice the only thing we're adding is a visual affordance of some morphing I hope you liked this gooey challenge and I'll see you on the next one y'all enjoy a few transitions