 Just whenever? Oh, we're going, aren't we? All right, fair enough. I suppose we should do an episode at some point then. Haven't quite thought of how to start this. All this time we spent sat here while it was all you said. That would have been the ideal time. Talking rubbish and not planning. Exactly, exactly. Hello. Hi. I'm not good at intros. I'm also not good at intros. You are Cassie Evans. True or false? True. True. True. And you work at Green Sock. At Green Sock, yes. And they do animation things. They do. And I do animation things too. Excellent. But there's going to be none of that today because this is my episode. All right. People can look forward to your stuff which is all going to be visual and exciting. Maybe. But I want to talk about the navigation API, which is not visual and it's all scripty. So nice gradient you've got there. Pick that, pick that especially. Yeah. There's a big website full of gradients, and every episode I go and scroll down it and I pick two. You'll see the other one soon. Oh, I'm excited for that. No, no, I use the exciting one for the title and the less exciting one to put code in front of it. So it's less interesting. Start with a bang. The navigation API is a replacement for the history API, which I think you've had some experience with. You used a couple of times. I have to look it up every time I use it. And that's totally understandable because it is a... I think when I started doing web standards and stuff, there was two areas of standards that had clearly not gone well. One was AppCache and the other one was the history API. We've managed to get rid of AppCache and this new API is how we get rid of the history one. So I built an example. This is a site I've been using as demos for various bits and pieces recently. It's you. It's me. So I wanted to talk about this topic at Google I.O. And they said, no, they already had too many talks. So this whole thing is like, well, fine, I've got my own show, do what I want. So that's this. So this is a single-page app and we've got a set of thumbnails of HB2 or 3D episodes. I'm gonna click a link and now we've just got the thermal ones and the URL changed, but it's a single-page app. It wasn't a reload. Just all changed in place. Now, just to make sure we're on the same page to begin with, what do you think should happen when I click the browser back button? It should go back to the page that you were previously on. Yes, okay. That was just calibrating. Yeah. I agree. So here we go. Back forward and back and forward. Yeah, correct. I agree. Okay, a little bit more complicated. I'm gonna click one of the videos and I'm gonna click one of the videos on the side. So that was two videos. So there was the zombie DOM one and now there's crossfading DOM elements. Again, the URL has changed for each one. We also now have a back button in the app. Like in the top there, we've got that arrow button. I'm gonna ignore that for the moment. What do you think should happen if I click the browser back button? Previous video? I still agree. This is good. Okay, because that's, yeah, back and forward, back and forward are the two videos there. But, and here's where it might get more complicated. What do you feel about this, the back button that's in the head of there? Previous page. Whoa, what does that mean? Not the previous video you were on, I think the page that you were on before. So we've had four entries so far. We've had, so we had the all of thumbnails and we had the surma thumbnails and then we had the two videos and we're now on the fourth of those. So what do you feel it should go back to? And I'm not saying there's a right and wrong answer here because like I made up an answer but I'm not confident. I think previous page at its base state, so like all of the, All of the thumbnails. All of the thumbnails. I think that's entirely valid. It's not the one I went with. I went with back to the, well, kind of what you said before, like the previous page. Yeah. And then now if you hit the back button, it's then going to go back to. But I think what you said there is valid. I think this is a kind of gray area of how browser history works. So we had these four entries because essentially browser history is linear. It has to be linear because you've only got two controls. You got back and forward. But yeah, we had two different opinions there about where that back button should go and neither of them were the previous entry in the history. We were both saying it should go back to some number of entries. And I think that's right because yeah, some of these like navigations, they feel more like a stack or something that it's kind of what you have on Android, that kind of thing. So to make that kind of thing, that demo work, well, first up it's like I was having to handle the navigations, capture them somehow and then do some kind of multi history entry traversal there at the end. Doesn't make the eye for this. All of them busted. Yeah. This is from the, it came from the days of HTML5 back when it was all being written essentially by one guy who did an excellent job at most of it. Maybe not this one. This is my other gradient, by the way. You can see why it's not as good as. It's not as good as it is. Sorry, I should have had a reaction to that. It's blue to a slightly different blue. So the API gives you these two things back and forward and they do pretty much the same thing as the browser back and forward buttons. We get this one, which lets you go back more than one or forward more than one. Just by whatever number you give it there. Have you used these before? Yeah, this is what I've used, the push state. So you get to set a state, there's the second argument, which is called unused, which is a relic of time and you just have to pass in an empty string or null or undefined or something and then the new URL path. So this is your single page app way of changing the URL without actually doing a full navigation. So if you've done an SPA style thing before, if you want to go from one section to another, we've got push state, you can call that whenever you want. But then the problem is like, when would you call it? And the solution tends to be something like this, where you have to add a listener to every link. So when that's clicked, rather than do the link thing, don't follow the link, we're going to do something else. Navigation API solves this. The navigation observation. That's a tongue twister. I was just waiting for you to attempt that. We get this navigator. And this happens whenever a navigation is going to happen, right? Look, it's named relatively well. So that's if the user clicks a link or a form is submitted, you get it for one of those as well. All of these things which would trigger a navigation naturally. And you say when it is about to happen? Yes, because you can prevent the default and do something else. So rather than add listeners to all of the links, you just add this one event. That's really handy. So this means that, yeah, you can have a separate routing element to your application that is just centralized here and it doesn't have to care about how the navigation happened. Okay, it's a bit of the API I'm less keen on. I'm less keen on this naming. So if you want to intercept one of these navigations, they call it transitioning from one history entry to another within the same document. I don't like the naming because for me, transition means animation. Yeah, animation. It's not that unfortunately. So there's some that you can't intercept. They should have called it intercept. There's some that you can't transition between and that would be like cross origin navigations because it's like that's someone else's website. You don't get to control that. But if it's same origin, you can say, hey, we're not gonna follow the link. We're not gonna do a page reload. I'm gonna handle this transition myself. And you get to do something like this. And you say, right, I'm gonna actually transition this while I do something else, like handle it in my application. And you can pass it a promise. And this is a new feature for this. Like it will do the browser spinner while. So even if it's an in-page navigation, you still get the little browser spinner doing its thing. Like the rest of UI acts like reloading some stuff. It's cool. And you also get an abort signal. And that's there. It will tell you if the user presses the X button or some other navigation comes in which has higher priority. So if you're doing like some fetches to get some data, you can listen to that and it'll stop the fetches happening or you can react to it in some other way. Like that's the navigation being aborted. There isn't an equivalent to push state in this new model because the whole idea is you just make the navigation happen as normal and then you pick it up in the navigate event. So it kind of does that separation of you've got one piece of code that is like you're clicking just clicking regular links and then this other piece of code which picks it up and roots it. All right, final bit. This is the history inspection problem. These are all really opaque titles. I thought like there's a series of problems. I had to try and group them somehow. And the inspection part is what we need to do this bit. Now he talks about the four like this one where it jumps multiple steps back. Yeah. I think this is almost impossible to do in the current API because the model we went for is it doesn't matter how many videos you've looked at when you click that back button in the top left, it's going to go back to the index, the nearest index I guess which in this one was the one filtered by Serma. I think it's entirely valid to have gone back to the first one as well but I just went back to the Serma one because that's the closest one. In the current history API, you get this and you have to figure out what number to put in there. And this is almost impossible to figure out because even if you go onto a page and you figure out like right, okay that last click I'm now one away from the index and then the next click right again I'm now two away from the index. That doesn't fully work and that's thanks to iFrames. This is a page. This is a page. That I designed myself. It's beautiful. Very brutalist. Yeah, this is what I've been using in my two year quest to figure out how browsers actually handle navigations and traversals. I should have done a simpler version of this but I picked it up because we've got free iFrames along the top there. And what I'm gonna do is I'm gonna navigate the top page to hash foo and then I'm going to navigate each of these iFrames. Now something that catches a lot of people out, something people don't maybe know about browser session history is that iFrames are included in that linear history. So if I click back now, I have to click, if I was wanting to navigate back to the top level I'm having to click that four times because it navigates each iFrame and then it's up level. And when those iFrames were navigated there was no event for that. There was nothing I was told like as a developer of the page, especially if the navigation happened entirely within the iFrame. So I could have been thinking like, oh, okay, so back to the indexes go minus two but one click in an iFrame and now it's minus three. It's just booby traps everywhere. Exactly. Yes. And that's why things like, you look at the code of things that react router and they've had to deal with all of this stuff as best they can. But we have the history inspection problem solution. And that's part of the navigation API. So it has these back and forward commands but they're different to the history API. But in a good way, I think, you can tell me whether this is, I think it's better. It's a little confusing in some ways. So back to where we were before, I've navigated the top level and I've navigated those free iFrames. But this time I'm gonna call navigation.back. Because I'm calling this at the top level, it's going to navigate the top level back and it's going to navigate as far back as it needs to to actually do a navigation of that top level. So you see where it says hash foo there? We run that command and now we've gone back to that bit. So you know, so you're saying to the top level, I want you to go back one. And that's what it's actually done. But it has also taken all of those free iFrames with it at the same time. When you say taking the iFrames with it, is that if you were to go forward now, would you go step through the iFrames? Yes, you would. Yes, so it has maintained that linear history. So it's actually taken us back one, two, three, four places by calling back once. So it's maybe confusing in its own way but it's more reliable from the pages point of view. I think at some point we might get an attribute that you can stick on iFrames to say, don't take part in linear history, please, be your own thing. And I think we need that because for things like a chat widget, you might have in the corner of a page, like a third party thing, you might want to manage its own history states but not mess around with the top level. With the page itself, yeah. Yeah, and we don't really have that right now. This is what the new thing gives us. You get to, say, show me your history entries for this page and it just gives you a list of entries and it will tell you things like the URL, their key, whether they're saying document. Look at all that information. And yeah, and you get to look at the state of each one as well. That's exciting. Just none of this you could do previously and you can also tell it to traverse to one of them. Same document as call. Yeah, well, it's stuff we should have just had from the start because the browser knows all this stuff already. Less busted. Yes, yes. I really hope so. So here's the code I wrote to make this happen, like this bit where we were going back and some number of history entries to get back to the index. As I say, this was totally impossible before, I think, or you might get it right if you were lucky or you were carrying loads of state around but with this new API, what I'm going to do here is, this is on that back button link, that back link click, I guess. If this new API isn't supported, just going to bail out, let it follow the link as is. Otherwise, we're going to get hold of these entries and slice them from zero to the current entries index. And that means now I've just got a set of the back entries because we might be in the middle of a set of entries so there might be forward ones as well. So now I've just got the backwards entries and now I'm going to find the last one which has a path name of slash or starts with with slash with because that was the, those index pages like with Serma, with Ada, with Paul. And if I don't have an entry, just return and then just a normal link click will happen. Otherwise, stop the link and traverse to that entry we found. And that's how that was done. Awesome. So it can just crawl back through the history entries, find the one that matches and just traverses to it. There's more that I'm not going to cover. There's stuff that handles like focus states, stuff that handles scrolling state that I haven't fully consumed in understood yet but I intend to because I think it's on me to update our article on this because personally wrote it left, never mind. But I think this is like it's taken that history API that has caused so many people so much pain over the years and that's heading for Chrome Stable. It's behind a flag, the web platform experiments flag right now but it's going to be stable in the next few months. That's exciting. It seems a lot more intuitive. I hope so because I don't think we get a third go at this, fingers crossed. Oh, and I forgot about this slide. Excellent. Okay, I'll do that bit again.