Transcript from the "Exercise 2: Solution" Lesson
>> Jon: Somebody pointed out a couple of things, yeah, if you have dev tools open. I think some people are having their tabs swallowed basically, where the focus goes in to the dev tools window after it's done on the document. And then as far LisIC MPM installing focusable but still getting the error.
[00:00:19] I'm not sure what error you're getting, but for now, maybe just to make it. I think if your It's not a node app, so you won't be able to require it. I think it's probably the error that you're getting, so let's, I guess, to kinda keep it simple, let's go over it together.
[00:00:35] But I think I'll just copy the content out of it. Okay, so back over on the app over here. And then yeah I closed that one, multiple versions of my app, okay cool so we've got this here. So yeah I'll pop open my code editor and go back to master all right and then we're just gonna be kinda living in modal.js.
[00:01:06] Hopefully everybody can see that,cool. So just for now I'm just gonna go to this GitHub link and I'm just gonna grab the actual string out of it. Basically all this is just a list that I made of like all the possible selectors for elements or focus-able elements. So we're just gonna copy that and then do something like, just for now, like focus symbol elements equals that giant string of things.
[00:01:35] Cool, so a couple of different things that we've got, so we've got our kinda selectors are laid out. So this is the modal, this is the button that triggers it, this is the gray overlay in the background, and this is the cancelButton. And then we have on the modalButton, when you click it it runs this open task.
[00:01:51] And then the cancelButton when you click at, it runs to this close task. And so we just kinda wanna add really not to much functionality to it but a little bit, it gets a little bit tricky with some of the like, key binding stuff. So one of the first things I'm gonna do, which is just kinda my general best practice is that always.
[00:02:07] Start it off by saving that active element, I'm probably gonna use it again even in this case where there is very little. On the document it's still just like kind of the way my line goes. It's like, always capture- before you change focus always capture what's currently focus.
[00:02:23] So, I do like Previously, I can't remember what I called it. Focused element or? Previously focused equals document.active element. Cool so now I've just got this in case I need it again. So then we got a couple of things going on. Like I think the big kind of like tough area is this Tab key trappings so you are, you need to listen for key down events and do all that.
[00:03:04] So we can have that event listener. So it's only tabs on the modal when the modal is focused that we really wanna listen for. So we can add an event listener for all keydowns, and then we'll just do something like trap, something like that. So whenever somebody hits the keydown event.
[00:03:22] Yeah, we're gonna just listen in there, we're just trying to see if they're using a tab or not. Cool, and so then basically we will basically just make this little function here called trap. And what we wanna do here is Basically, yeah, so it's a key down event, so it's gonna get the event tossed into it.
[00:03:45] And so what we'll wanna do is list and if the event, and then we can listen to the key code. So if the code key equals, and I wrote down here cuz I never remember them. So it looks like nine is tab and you can just look these up online, I don't expect anybody to know what they are.
[00:04:02] The other way you can do it is you could, how I do it, [LAUGH] is I console log event.keycode, and then I refresh and then I hit tab a bunch. I'm like, okay, I see, it's nine, I don't, that's me. [LAUGH] Cool, so then we basically have two different cases here, which is shift Is held down, and then later, Shift is not held down.
[00:04:25] And that's just, this is backwards, the other way is forwards. So then we can just do if e, and then it provides a nice API, so if the Shift key is held down, so now we're Going backwards. I think one thing that I forgot to mention is that we take this focusable elements but it's not all that useful to us as a string so I'm just going to move it.
[00:05:07] But so basically we'll want to do, instead of just this string we can do something like modal.querySelectorAll on it. So for those that, again, if you're more of a jQuery person, you could just pass in a jQuery selector with this string as well. Whatever works for you. But basically, instead of just a string, which is just some words, we want To select all of those elements inside the so this will provide us with a dom list any focus-able item that's on there.
[00:05:38] And then the last thing we'll want to do is turn it into some kind of array. And I know we've got people from all different levels here so hopefully I'm not boring the advanced people but not like making people that don't do a bunch of java script feel really confused.
[00:05:52] This is just like very domain specific, so you can just do like whatever array prototype trick. Slice and call it with itself focusable elements. So basically, yeah, we select all the focusable elements and then we just turn them into an array. And so now we have this like nice list, so you can do things like, var firstItem = focusableElements
[00:06:21] And then you can do the var lastItem equals focus-able elements at focus, I should have gone with something short, length minus one. Okay so all that code aside basically this is just allowing us to get the first focus-able thing in the and the last focus-able thing in the.
>> Mark: Like is spelt wrong, says you.
>> Jon: Thank you, Mark, I didn't mean to get defensive.
>> Speaker 3: [LAUGH]
>> Jon: Thanks, okay, so cool, so now we've got these things going, which is cool. And so now that we're in here, We know very specifically what we're looking for. So if we're moving backwards, and if the document.activeElement.
[00:07:07] And remember, so we store it in a variable when we very first begin. And that's the element we're on before the modal launches, which in this case is gonna be the button to launch the modal. But remember, document.act development is gonna keep updating as you're hitting Tab. Like it's changing every single time you move around.
[00:07:25] So we have it stored here as previously focus, but the second the user hits Tab, the actual result here is gonna be changing. So Now that we're moving around, if the document active element is equal to the first item, so if they're trying to move back and they're as far back as we go, we can just do that same kind of thing, event.preventDefault, so don't let them go.
[00:07:53] And then we take that lastItem and we call .focus on it. So that's kind of the whole basic idea there. And then here would be four words so then it would just be ifdocument.activeelement is equal to the last item, event prevent default.
>> Speaker 4: I think you want that else to be outside the shift key.
>> Jon: Yes, you certainly are right. Let me try to grab this sucker here. Ok. So this is the if we're moving backwards, right? We still want it to be inside the shift key.
>> Speaker 5: Do you mean that if.
>> Jon: Yeah, I screwed this up. Okay, so yeah, if it's tab and that's this block and then if it's shift key, then that's that block Yes, thank you very much.
>> Jon: Okay, so if it's Shift, then we're moving backwards and the only thing we really care about is if it's the firstItem. So then here, if it's not Shift we're moving forwards and the only thing we care about is if it's the lastItem And then if it is the last item we call focus on the first item.
[00:09:09] No we get my.
>> Jon: Okay, sorry if that was confusing, I start. Stuck it in the wrong place but basically it's the same as a pseudo code logic it's just a little bit more verbose and confusing. So basically it's just like forward or backwards and then all we care about if they're trying to do something we don't want them to do which is move past the bounds of the modal.
[00:09:32] So let's kinda see where we're at here, so I click it and then I tab through, it does not work.
>> Speaker 3: [LAUGH]
>> Jon: Wonderful, okay, one second. I think I did.
>> Speaker 5: It's on 931.
>> Jon: Yeah.
>> Jon: Okay, cool, so yeah, so now we can kinda [LAUGH] tab through there.
[00:09:58] Man, this live coding, so good and we can go backwards or forwards and stay in the model yeah
>> Speaker 6: Is this kind of a tab trap though because you can't tap back into the URL bar.
>> Jon: So as far as, yeah tap traps are interesting because they can kind of be a little bit of an anti pattern.
[00:10:15] So my understanding and it's subjective at this point is like, so you can still get to the URL bar with command dollar control out. Which I think a lot of people use, the other thing is if you're gonna be tap trapping. You need to also respect things like escape should close the model and get you back out of the tap trap.
[00:10:33] So I think they're a good practice as long as you also give users an easy way out. I think those go kinda hand in hand which is why I have them both here, yeah.
>> Speaker 7: And Victor is asking, should we also check if the user presses escape key to close the model?
>> Jon: Yeah, yeah, so then the last kind of thing that we'll want to do here is, let's see. Okay so that was if event shift key. Get my and then else if (event, and then you could listen at the keyCode. And I think it's, I wrote it down, 27 for escape.
[00:11:04] Again, we could console log or look it up. And then we could just call that close method. So now we can go back here.
>> Speaker 7: One little hint. Victor posted a nice little link to Keycode.info.
>> Jon: I've used that before. [LAUGH] Keycode.
>> Jon: Nice. So tab is 9, escape is 27.
>> Speaker 8: I'm working on a, what's it called, mark down editor right now cuz I'm taking notes. And they actually broke the conviction when you hit command L it asks you to enter a line number it pops up a little alert window.
>> Jon: Yeah we've fall into, I've fallen into that in a lot of jobs where you're like, so you want to do like keyboard short cuts your own.
[00:11:46] But I think it helps a lot to do a little bit of research on what the conventions are especially the browser ones you should not. So it's like you know this, it's kind of similar to people hijacking the back button which is a very popular thing still to do.
[00:12:01] Or in like another accessibility thing in the same vein is like for a long time browsers like chrome what they expected delete would go back a page. And if you're in google and you went to Facebook any hit delete it would go back a page on but apparently was having accessibility issues with like.
[00:12:16] You're gonna get a form or something like that and so they've bowser and just very, very recently moving away from that. And now I think they want control in the left arrow or command in the left arrow instead. So, I don't know if anybody uses Chrome and noticed for like the last month or so when you would hit delete, it would have a little thing that was like, nope, you gotta do command left arrow.
[00:12:35] So it's kind of in the same thing of like you want keyboard shortcuts for your app, but then there's keyboard shortcuts for the browser. And then there's ones for the operating system and everybody kind of has to play nice with each other.
>> Speaker 8: And there are only so many keys.
>> Jon: Yeah, right exactly, unless you get a bigger keyboard or like five key combinations.
>> Speaker 7: I think that also really just supports the principle of providing multiple ways to do the same thing because one may end up actually no longer. No longer be supported.
>> Jon: That's true. Yeah, that's a really good point, too.
[00:13:08] Yeah, I think, and again a lot of the stuff, I think, is just, I think one of the reasons accessibility is difficult again goes back to it kind of being a moving target where it's like. It's not as simple as run your website through this checker and it tells.
[00:13:23] I mean, there are great tools that we're gonna cover, but there's still stuff where it's, and that's a great question. Okay, I'm helping users tab through, but now I'm hindering them changing the URL, you know what I mean? And you're kinda trying to Trying to think of these different things.
[00:13:36] I do think there are some good best practices, which is what I'm trying to do here in the workshop. So again, tab trapping's great, but provide that escape path. Which is a pun, cuz it's literally the Esc key. I made that up right now, thank you.
>> Speaker 9: Is there like a, sorta, best practise to Like if a person using this reader and they wanna discover keyboard shortcuts, is there like this is how you get to it for most [CROSSTALK].
>> Jon: Yeah, I think the most common practice is the question mark. It's where a lot of people put there. So with nothing focused, hit question mark. But like I was kind of mentioning before, at Twitter, we did that kinda neat thing where we have a div that gets injected to the top that is tabbable but visually hidden.
[00:14:19] And so it's only for users that hit Tab right away, they'll have this thing read to them. We don't give it a display, but it will be focusable, so a screen reader would be able to read it. So if you go to Twitter with a screen reader on, and you hit Tab, It'll just audio, it'll read you something that's along the lines of, we have keyboard shortcuts available.
[00:14:39] Hit question mark to see what they are that one's extra engineering work. I would just hide it behind question mark as the easy way to go.