 We all make mistakes. Sometimes the mistakes we make are very small and they don't really matter too much in the grand scheme of things. Other times we make bigger mistakes that can actually be pretty problematic. And I actually found one of those mistakes in an old video of mine, and it was so bad that I did something I've never done to one of my tutorials before. And I won't lie, I'm actually kind of ashamed at myself for having made this mistake previously. And so let's actually jump in and watch the video and see where I made this mistake. I'm gonna watch this one together. So let's hit play on this. And I've set up a div class menu toggle here with a div. And there's the first glaring error, which is the one that made me take this video down, which was using a div instead of a button. Just to sort of compound this issue a little bit, I did change a little bit more here. And it's something that will be clickable. So I wanna change my cursor to pointer. Making something of cursor pointer makes it look like you can click on it. And of course, we can add JavaScript to actually make it clickable, which is what I eventually do and actually use some jQuery for that one in this. But it doesn't solve the problem of why we shouldn't be making the div clickable and why we should actually be using a button for this. We're gonna look at why these were wrong, how we could fix them all and do things properly. And so let's jump on over to VS code where I've taken all of the code from that original video and I've put it in here. And we're gonna try and fix this. And we're gonna look at the very first thing, as I said that I did wrong, which was right here where I used a div instead of a button. And I already hear a whole bunch of full stack developers going, this is completely fine. You just add the functionality in with JavaScript and it doesn't make a difference. But there's a whole bunch of stuff that you probably are missing if you're turning a div into a button. So the first thing is I can't actually focus on my button if I want to keyboard navigate. If I try doing it, it's a div, it doesn't work. Ah, but we can fix that, right? And yes, we can fix it by adding a tab index of zero on there. There we go. Wrapped up, we're ready to go. Add JavaScript to get everything working. Except the browser and assistive technologies still don't really see this as an actual button that can be interacted with. So there's another thing that we'd have to add. And we can do that. It's not too hard. You'd give it a role equals button. And now, as far as browsers are concerned in assistive technologies, like screen readers are concerned, this is actually a button that can be interacted with. Awesome, done. Add some JavaScript to make it work and we're good to go. Ah, not so easy. There is another problem which is buttons need to be able to be interacted with by clicking on them, but also by being able to use your spacebar or by using the enter key. All three of those should work. And so if you wanted to do it with a div in your JavaScript, you'd have to be looking for all three of those possibilities. If you use a button, you don't have to do that. If we delete all this and you say this is actually a button instead, then it works perfectly fine with just listening for clicks. By doing this, first, we don't need to add those extra attributes. All of it comes baked in and we're good to go. And we can write a lot less JavaScript because we just have to listen for clicks and nothing else. And all of that functionality is there. This is focusable. It's seen as an interactive element. And you might be saying, well, then I have to write extra CSS to actually style my button because now it looks really terrible. So this is my menu toggle right there. Maybe you feel like you have to, but I can just do a background of transparent, a border of zero and now my button looks like it did before. So it's not like it's that much extra work in the CSS and it's a lot less work doing that and maybe a few other small tweaks that you might need. Then the extra attributes you have to remember to put every time on your clickable div plus the extra JavaScript that's listening for all the different things that you'd need to actually make that work. I guess it's a little bit off. So let's just add a little extra space on the top there just to move it down and we're pretty much good to go. But I did mention there's more mistakes than this that I made along the way. And if we just look at the HTML right here, maybe you know what the mistake is right away. And if so kudos to you, but if you don't see it, it's my button shouldn't be down here. So on the menu, let's just turn off the CSS. So it's actually visible right now. What I'm gonna do is I'm gonna come on here and I'm gonna tab through and I'm tabbing through and I'm getting my different items and then I'm hitting tab and it's selecting the button at the top. So the button is selectable, it's focusable. That's awesome. I can interact with it with my space bar, all of that. But the problem is like, if I end up on the site and I start tabbing through, it kind of weird that I have to tab through all of my list before I get to the button. Doesn't make much sense. So ideally where this button should go is either here or even better would actually be inside the navigation. And this is the best place to put a button that's actually going to be opening and closing a navigation menu that's hidden off screen or whatever it is. And the reason for that is if somebody is using assistive technologies, they can actually skip straight to the nav. This is a landmark region that's very easy to access with assistive technologies. So if they navigate straight to here, the first thing in there is the button and they can interact with that and actually open the navigation right away. So that is the ideal place. I realize every now and then it is possible that you can't do it for some reason. But if you can, you do want to put it in there. Now by me putting my button in there, if I hit save, it actually breaks things a little bit. So we do have to fix my styling and we'll look at that. And we're going to look at the CSS a little bit in this one as well. But you can see the button's actually in the wrong place because of the way I've positioned things, but it's not a hard fix. The other thing though is that if you do need to have it outside, again, it should be before, not after your navigation. And in those cases and generally all the time, it's a good idea to say what this button is actually controlling. So what we can do for that is on here, give this an area controls and areas for assistive technologies to give it a little bit more context to the purpose of this button. So area controls, primary navigation and this obviously needs to be linked with something and you do that with an ID. So here on my UL, I can give that an ID and give that the primary navigation. So now we've given it a little bit more context but we haven't given it enough context because imagine if somebody is coming through here, it's not a sighted user and they come across this button and the screen reader just reads out button. That doesn't really tell you much, does it? You don't know what the button is for. If we're a sighted user, we see it. We can sort of infer what the purpose of it is. This is kind of useless and I probably would have been better with an SVG to be honest but whatever. We made it work with just a div with some pseudo elements on there. It doesn't matter, it's really decorative. So first I could do an area hidden equals true on here just to say like, you can ignore this, this isn't important and what we can also do is add either two different ways. You can do an area label here and put menu or main menu and put menu here to let it know that we're opening and closing a menu. So it's gonna say button menu and then they know it's further navigation menu. The more common approach that I actually see than using an area label is to actually include text in here and we can do that with a span and I'm gonna call it visually hidden. We'll look at the CSS for this in a second and in here we just write menu and it's actually encouraged to leave this menu text and it's positioned and it's all mucked up right now but it's encouraged to actually keep that and just have it like underneath your hamburger or something like that but obviously the designs we get from our design team often don't include that. So if we do wanna hide it, we can use a visually hidden, a lot of frameworks and other things also call this SR only for screen reader only where we hide the text visually but we keep it there for screen readers to give it that extra context. So jumping back over to my CSS, I can add this class in here and you can see it's actually taking the text that was there away and we don't see it anymore and if you'd like more context on this, I've included a link to a really good blog article by Scott O'Hara that goes into more detail and you can get the code from there as well. So we're hiding that. We're not using display none because display none would actually take it out of the DOM and make it completely useless because then a screen reader won't see it either. So we need to hide it visually, not display none it and make it just disappear. So all right, we've added some context. We now have a button rather than a div. It's gonna click, people can interact with it properly using any controls. We're saying what it actually controls and what we're gonna be opening and closing, positioned it in the right place. We're off to a good start and made a lot of improvements so far. There is one more area attribute we're gonna add here and this is going to be, we'll add it over here. And so for these actually, why don't we come and just wrap these down just to make it a little bit easier since we're gonna have so many of them. And this one's gonna be an area expanded and we're gonna write false. And the reason, I mean, it's true right now because my menu is open but by default it will be closed. And so we're saying that this controls my primary navigation and we're saying that right now the navigation is closed because by default it will be closed and when we click it's gonna toggle and it's gonna open it. Navigation menus are one of the few things where these area attributes tend to be required. There's a lot of things we're just using the right semantic thing like a nav here and not having to put role equals nav or using a button it comes with a lot of the accessibility features built in but there are some things when you're building them out you do need this extra context and it's not that hard to do and once you've done it once you have it there forever and you can just use it for all of your projects. So area expanded is false and we're already gonna be using JavaScript to open and close things and toggle stuff anyways and so this is just another one of those things this will get toggled using JavaScript from area expanded false to area expanded true which we'll look at doing in a second. And so before we get to our JavaScript let's just fix the CSS up really fast and to do that let's just look at how we have this setup right now I have my site nav here which is my entire navigation then we have my button and then I have my UL that's right here and the way I had originally styled things up because I had my button outside of the site nav is a lot of the colors, a lot of the positioning all of that wasn't done on the UL it was done on the nav element itself. In this case I don't wanna do that so I think the best thing to do is I don't like using IDs in my CSS if you do you could just use your ID of primary navigation but I'm also gonna give this the same class primary navigation so I can hook into it that way in my CSS. So here where I had my site nav and then I have this UL stuff down here I can just make this my primary navigation and I can move all of this stuff that was on there and put it all on this one right here and you'll notice right away that also fixed my button up and everything is pretty much good to go so it's nice when that works now depending on how you organize things maybe you need a position relative on the nav itself and all of that but in this case I don't need that and now we can actually comment this clip path back on so then it's hidden and the idea is when we click it toggles between the old way and this new way right here and originally I was doing that with some jQuery where we were switching from having we were toggling the class on and off basically of site nav open and I was also adding an open class to the toggle itself just to cross them and on cross them so we're gonna replicate this really fast with vanilla JavaScript so we don't have to rely on the dependency of jQuery for something simple like this and so here is the JavaScript version of it instead of the jQuery version so first we just have our menu toggle here so we're selecting the toggle itself, the button and then we have the primary navigation that I just added so that is the UL that we're selecting right there then we're adding an event listener for a click onto the menu toggle and remember if this was a div and not a button I wouldn't be able to interact with that properly with a space bar or with my enter I could only click on it or push if I was on a phone and there's a lot of people out there who use keyboard navigation hi all you vim users out there you know this is an important thing to be able to interact with them properly I only because we have a button the click listener is listening for all of them if it was a div we'd have to build all of that in in our JavaScript to make sure we cover those cases now what we're doing is we're toggling that class of opened on the menu so that's just crossing the X that's right there and then we're also toggling my nav opened which is just making the clip path come and go and we feel like we're done but we're not done and if you remember when we jump back to our HTML over here we have the area expanded that is false that needs to get toggled over to true and we're gonna sort of change a little bit of how we did this since we're gonna be doing that anyway so really the first thing we should be doing when somebody clicks is we should be looking to see is the navigation already opened or not so one way we could do that is by this right here and so we're saying we're creating a variable called is opened and we're getting the attribute of the area expanded so it's is opened is equal to false right now and if we click we wanna turn it to true so this is really going and it's grabbing whatever it says in the quotations right here so by default it will be false if it's false we wanna do something we wanna open the menu and if it's true then we wanna close the menu so to be able to do that we can come in with something that looks a little bit like this where we're saying if is opened is equal to true so if our menu is opened we want to set the area expanded to false so we're closing it and then or else because we only have two possible states then we're switching it over to true so if we do that and we hit save we should see this is actually working so when I click you can see the area expanded switches over to true and then it goes to false and then to true and then to false now the first problem with this is you'll notice this is in quotation marks and that's because when we get an attribute with JavaScript we're not actually getting a Boolean of true and false we're getting the string true or the string false so to make this instead of it being a string into a real Boolean of true and false what we can do is do is equal to true as a string and what this means is it's a little bit different and this is coming from a commenter on a previous video and I couldn't find your comment I do apologize but what this is doing is it's saying it's comparing these two so it's getting the attribute area expanded if area expanded is true it's gonna return an actual true value and if the area expanded if this is actually equal to false then it's going to false is not equal to true then it's gonna return false so by doing that is opened is actually true or false so one nice thing with that is we can actually then take this off and hit save and it's still going to work so we can see it working away there and that is awesome but we're not done yet we can improve on this a little bit more because whenever I write JavaScript and I write things out this way people tell me I could do it in more efficient ways even though if I do that with my CSS and I use new CSS techniques people say that it's harder to read and that it should be more verbose because then people will understand it better whatever let's make this just to show you the other option that we have here if nothing else where and I guess it does clean things up a little bit because what we could actually do is we could turn some of these things into their own function so let's do that we're gonna say function open menu now it doesn't really make sense to have these happening inside of a function where we're switching them and these as toggles one issue with the toggle as well is if the initial state somehow is wrong you're toggling it like the inverse way whereas here we're actually checking for things properly and it can only go to the correct state so one way we can actually fix this up a little bit and I think the first thing we can do is actually delete this open class we don't actually need that anymore so we're gonna delete that completely and obviously that's gonna break things because now my thing will never cross and we wanna still get that nice little X happening so if we jump back to my CSS and we scroll down to where that was happening my open we can see it here with my hamburger so we're just changing we have rotation basically happening on some suit elements there's really nothing fancy that's going on right there but here what we could actually do is on all three of these opens and I'm just pushing control D on my keyboard to select the same thing in multiple places if you're on Mac it's probably commandy I'm gonna do an area expanded is equal to true so if my button has an area expanded of true that same thing is gonna happen I don't need that open class on there anymore I can rely solely on that and look at that it still works and everything is fine and the nice thing with this is you sort of are forcing the accessibility and having this built the proper way because we're hooking into those accessibility features in my CSS to style it based on what's happening there which is what's telling us the story of the situation so we have my X is actually happening and I'm super happy with that and this setup is only gonna work if your button and is right before you UL and again this is how it should be set up ideally we'll look at a solution for the times where that can't happen but if this is right before this there isn't something else we can do which is let's scroll all the way up here where I had my site nav open we don't need this class here either what we can do is say area expanded is equal to true but if we have a direct sibling so the sibling that follows immediately after it's direct is the wrong word here it's escaping me the correct one but the sibling that comes immediately after is my primary navigation now we should have brought everything back in and we have that one area expanded controlling everything as I said I'll look for I'll show you a separate solution that we could use here as well but before we do that let's fix up our JS a little bit so we don't actually need this anymore either and then we can just take this and this is for my menu open so that means we're setting things to true so that can go right here and then we can duplicate that one this can be my close menu and in this case this will be getting set to false so we can delete all of this and then we can get fancy by saying if is opened and then we put a question mark we're gonna do a ternary operator I think that's what it's called so we're gonna say is opened is my navigation opened if it's true then we want to close my menu close menu and if it's not true then we wanna open menu and so a little bit more concise compared to what we had before and I don't think we need this anymore oh that's all in my event listener yes we do still need that okay so there we go so we're checking is this true or false if it's true that means it is opened so then we wanna close our menu if it is false if it is opened as false then we skip over to this one on this side and we open our menu so let's double check and see if that's working everything still works and that's awesome we feel like we're home free we feel like it's done but there is another problem and that problem is right now I can tab onto here to select it through keyboard navigation but because those elements are still there they're actually completely there because they're really just being hidden by like a clip mask here so let's just change this circle to like 150 pixels or something so we can actually see them a little bit and if I tab again I'm selecting my home so that means if somebody is like if I tab again and then I tab again I'm tabbing onto things I can't see and in general if something is hidden away and if something is hidden we shouldn't be able to actually select it in any way for keyboard navigation or anything like that so instead of having the clip path on here what we actually wanna do is display none it we wanna take it off you could I guess do things with tab indexes and try and make it so it's not selectable but you could run into issues with that along the way and the problem with doing this is it's also gonna break our animations we're gonna have to fix our animated look at all these problems that it seemed like such a simple thing I threw it together and it's one of these mistakes that people make and then when you start trying to do things correctly you just run into this waterfall of all these different things that you need to do but doing them correct is the right way to do it and it's our job as a developer maybe the other way is the easy way it's very different from like building a bridge because there you're really putting people's lives at risk right? Where like you could literally kill someone if you don't if you take shortcuts but it's the same idea that if you make something shoddy and really bad that could cause problems maybe the first 100 people to go across that bridge it's fine and then all of a sudden it crashes that's a big problem if it's more of a silent issue when it's a website that doesn't function properly but it's just like the engineer's job to build that bridge properly and design it and do all of that we're developers working on websites it's our job to do it properly even if it means you need to put more work into it like we're doing now so you might be saying Kevin this is ridiculous it was looking fine before it was looking fine for like a very specific use case and a lot of things could go wrong if we want to do it the right way in the correct way we have to put the work into it sorry for the little aside there but I always get some pushback against stuff like this so I just wanted to cover all my bases there so yeah we want to make sure that this isn't tabbable or reachable the content is gone and we can do that by back here you can see I have a comment out of display block this is where things get a little bit annoying now and we'll look at why it's not that hard to fix but it is good to understand because what we want to do is if it's my primary navigation normally is going to be a display of none and this will sort of actually link into that JavaScript solution I was talking about because I think one thing that's nice to actually do for this and it makes it a lot easier on the CSS side to hook into everything is on my navigation if we add in something here like data state and we're gonna say closed so by default the state of this navigation is closed that makes sense right and then when we click we want it to open and because we have these functions here it's nice and easy just to come in so we're gonna use site navigation when we open our menu we're gonna have our data state is going to equal to opened and here let's just copy that paste it down here and then this becomes closed and here let's find my UL right there and you can see data state is closed and if I click it goes to open and it goes to closed and it goes to open so by having that it gives us something to hook into our CSS and it also means here as I said if you don't want this and you don't wanna do the area expanded that way you could always come here and have your primary navigation and this probably clean it up and then in here do your data state is equal to open or opened as I said opened so by doing that it should still work perfectly fine you can see it's still working I haven't fixed my clip path yet we'll see why in a second and that does mean that if you now wanted to move this button you had to for whatever reason you wanna leave it here but if you can't for some reason and you have it outside of your navigation the styles and everything will still work so that fixes that JavaScript thing that I was gonna talk about and then what we can do here is have a closed and then we just do my clip path here clip path of circle at let's remove this from here actually and then we can do the circle is my 0% at top right so now that should work there we go we're back to having that functioning except when it's closed that we said this should be a display of none and when it's opened this should be a display of block that ruins it though because now my navigation or my animation I should say has vanished the reason for this vanishing is when we go from a display of none to having a display on something the display of none like this doesn't really do anything because it's display none it's not there so any other properties that are on there are sort of like as far as the browser is concerned don't really matter we're just turning on display block it's there now and these are what are applied to it so even though we're transitioning on my primary navigation here that transition is not actually doing anything at all it sucks but it's just part of how all of this works so we need to come up with a solution to that and there's a few different ways we can do it we're gonna you can even do like a mutation observer I guess to me that's way too complicated than for something like this but just one extra step and then we can get this animation working once again and to me the easiest way to do that is actually to remove these clip paths from here and instead of having the clip path here is to use CSS animation we could do it as a transition when we're closing but when we're opening it just won't work so we're just gonna do the key frames in both directions because I think it's easier to be consistent that way so at key frames I'm gonna make it very generic we could link this animation in specifically for our navigation here but this could be an animation that you could use in different places if you had this for your circle that opens up it could be something that's in multiple places so we're just gonna call it clip path circle open and then at 0% and oh forgot my R so at key frames there we go I knew it was wrong because the percent thing here was kind of weird so my key frames I copied this in before when I was doing it so when it's opening it's starting at the zero and then we can duplicate that line this can go to 100 and I think it was at 250% I used a really big number to make sure since it's a circle I just needed it to be bigger than what the actual thing was this number could definitely be tweaked and then because of the way key frames work if you're toggling animations and you wanna like switch change an animation that's on something even if you're just trying to reverse it if the name of the animation stays the same it can be problematic so it can seem a little bit annoying but we're gonna duplicate that and we're gonna do a circle open and a circle close here and then this can be my 100% this can be my zero and you can leave it exactly like this if you wanted to and it would still work because the key frames don't have to be in order they just have to it's all based on the percentages but I'm assuming most people like having them in order but we'll just put it like that and then we can bring those animations into here now it's not going to completely work for the closing state but it will work for the opening state and I'll explain why so when it goes to open we're just gonna do an animation open and I think it was 750 milliseconds it's a little bit slow but it looks nice and let's just do an ease in out and we have to leave it forwards on here because with an animation if you don't do forwards it resets back to zero at the end so now if I open it it appears if I close it it disappears but it just disappears so you go, okay, Kevin let's put that animation on the closing one and we're gonna do clip path close but it does the same thing it opens really nice but then it just closes and that's because maybe our animation's running but we have a display none and it's completely vanished huh, okay so what can we do for that? Well, luckily it's not that complicated and actually let's change the order just because I like sort of going from opened then we're going to duplicate this one let's duplicate this one and so on my closed state the only thing is my display none in the middle state the only thing will be my animation and we'll call this closing maybe you have an idea of what's happening here so what we're going to do is we want to when we click we want it to go onto closing run that animation and when the animation is finished we want to close it and switch over to the fully closed state sounds complex but it's not so bad we only need this on our closed menu because the open menu is working perfectly fine it's only on the close and I said I'd explain why that works we have a display of block that comes on because that animation is on there and that animation starts at 0% the animation's there right away it's starting at that 0% unlike the transition that was happening before where the transition would just there was no transition because we had nothing to transition from because it didn't exist before and now we just have this finished state that's there so the animation makes sure that the animation actually runs so when we close our menu we want the area expanded to go to false that's fine but then instead of going to closed we want it to go to our closing which is the animation that's going to be running and so now if we do it it's going to work we can see that it opens and then we can see that it closes so that is fine and it's working both ways but now when we get to that closing state it's still closing so we've never hit that display of none I could still keyboard navigate to all those things that are just hidden away from us visually because they're hidden away by the clip path so we do still need to get to that finished closed state and we're going to do that by adding another event listener so we're going to come here I'm going to do my site navigation because this is where the animation is happening on so that's what I want to listen to I'm going to do an add event listener now we have to be a little bit careful with this and this is a mistake that I've done before where you could actually stack your event listeners on top of each other and have like 25 you know if you keep opening and closing your menu every time you add that event listener again there's a way to prevent that from happening which is really easy but here what we're going to look for is instead of a click or anything we're going to look for an animation end and when animation end we want to do something so a simple arrow function and then all we need to do is set the attribute to closed we're not completely done but we're getting there and just to show you actually here let's do a console log console log closed and so if we take a look in here and we'll go over to my let's look here first so it's closed let's open it we can see it's opened when I do that it's closing and then when it gets all the way it's closed so it looks like it's all working and kind of cool right you can see all like the different states happening as the animations are running and everything but wait now my anime it keeps closing on me all the time and that's because we have that event listener that we added here and that event listener is never going away and I mentioned that let's go in my console and it's actually we have 16 of them let's refresh the page here and then let's open it and let's close it and we should get it closed we got one let's open it and it just did it again and then we can close it and then we're going to get it now we have four we went from two to four let's open it right six and now we're going to get to nine and that's because every time I'm doing this it's just adding that event listener again so we have it listening three times and then four times and it's listening even when it opens and we don't want any of that happening so to make it so it listens and then that event listener goes away and leaves us alone right here after the curly brace we're going to do a comma and opening close curly braces again and right once is true and by doing that it means it's going to add this event listener that's fine once that event listener has found what it's looking for so it's found this animation end it's going to go away and it's going to stop listening it disappears into the ether so now if I open it works if I close it we'll get our closed but now if I open it again it works fine there's no more event listener looking for that animation so it's not destroying so it's not displaying everything again and then I can do it and it only adds it once and that was definitely more work than when I did it the first time but we did it properly we did it right and everything I think is functioning properly let's ignore the fact that on the desktop layout I used floats let's also ignore the fact that I probably could have done the icons in a little bit of a better way and instead focus on this great video that is right here for your viewing pleasure and with that I would like to thank my enablers of awesome Jan, Johnny, Michael, Mr. Dave, Patrick, Simon and Tim as well as all my other patrons for their monthly support and of course until next time don't forget to make your corner the internet just a little bit more awesome