Transcript from the "Active Element & Tab Trapping" Lesson
>> Here's another thing that you can do, some really cool stuff with. There's a DOM API called Active Element, and Active Element will return the currently focused element. So in our example up here, where we have this let's button focused, right? It's got the blue focus ring around it.
[00:00:18] If I were to open my Chrome DevTools and do document.activeelement, we would see that this button with the let's it is the currently focused item. So what is that used for? One example where I've used it in the past is when you have a page transition, and it's important that when you go back from that page transition that you return the user to wherever they were.
[00:00:43] So thinking about a social network like Twitter, which has a big list of tweets that you can cycle through, and then when you click on a tweet, it brings you into a modal of the tweet itself. When you close that modal, users are going to expect to be returned to the tweet that they were focused on, right?
[00:01:01] They're not gonna expect to be sent back to the homepage at the top, which would be the default behavior if you just close the modal. So for example, on social networks, what they'll do is when the modal button gets clicked, it's about to be opened, they'll cache the active element and a variable, and then let you open the modal.
[00:01:17] And then in the modal close event, they'll call.focus on that cached variable, so that when the close happens, they call.focus. Which will not only give the focus ring, it'll put you in the tab index of where you belong, and it will also move the screen if necessary. So if I call focus on this when I'm scrolled up, it'll refocus on that.
[00:01:36] So that one's pretty helpful. Again, single page apps where you expect the back button to work, right? Especially anything with an infinite feed, you can imagine if you're scrolling Instagram for 20 minutes, and then it just shoots you to the top and you've lost your place. And you have to look at puppies all over again.
[00:02:10] But tab trapping, so the concept here being like imagine that you have a button that makes a modal. And let's just say as an example, it's like a login screen or something like that. So you click on the button and a modal opens up, and the modal has a form to fill in or something like that.
[00:02:29] So as a keyboard only user, if I keep tabbing through to kind of see what's going on it'll tab me to the index or to the input, and the other input and the Submit button. They keep tabbing what's happening to this button, again to this button, but if I hit Tab again, you can see it focuses me all the way back out here.
[00:02:46] And if I keep tabbing it's actually gonna start focusing on the web page in the background. Again, keeping in mind that while for all intents and purposes, it looks like the screen is blacked out. That's just CSS doing that, like the page is still open. And so what can happen here is that keyboard only users can very easily get themselves totally out of the modal.
[00:03:21] And you grab the last tab-able element in a modal, and then you listen for like a key down event. And if they're on the last element hitting tab, you focus them on the first element. And if they're on the first element hitting Shift+Tab, then you focus them on the last element.
[00:03:39] And so basically you're kind of using a lot of those techniques that we learned like storing active elements, calling .focus on them, listening to keydown events. We're sort of using all of those together to create this experience of really being on a modal. So the keyboard only users feel the same way that non-keyboard only users feel.
[00:03:59] Does that make sense at a high level, like tab trapping, keeping users kind of locked into this modal or trapped into this modal? Great. So yeah, so for an example here, the modal that I'm using, let me see, focus management. So, I just went online, I found some modal library.
[00:04:19] It's not my recommendation, it's just a library I found called Tingle. It creates this modal, so it sets the content to a big string here of HTML, and then it adds these footer buttons. This is just their demo, right off their website, basically. So then I have a button here for those that do a lot of JS development, is just get element by ID, the button.
[00:04:40] So when the button is clicked, we call modal.open. And so what we'll want to do here is we'll want to basically grab the first element which I can see is this input. And we'll wanna grab the last element which is this footer button here which again, if we go back over to the website.
[00:05:00] The first element should be first name, and the last element should be dangerous action. And then we'll wanna put our listener in basically, right? So, I went ahead and did it, and I just kinda wanna work through the code together on it, just so we can see again.
[00:05:41] And then you could do document query selector all, that focusable string, which will give you an array of focusable items. And then you could access the zeros and the length to get the first and last on that array. That would be very dynamic, so if people added more things to the modal or took away things, they would always work.
[00:05:59] But for this kind of short example I just manually added a class, hey, this is the first element. Hey, this is the last element. And then I grabbed both of those into variables here. So we've got the first element is the one with the class of first, last element, class of last.
[00:06:12] And then really all I did here is that a single event listener for the key down event. And we just look and say, hey, if the key hit was tab, or the key code of tab, then we go into this if, we say if word shifting, meaning we're moving backward.
[00:06:29] And the currently active element is the first element, so for on the first element trying to go backward. Then we take the last element, we call focus on it. Otherwise, so we're not shifting, we're going forward. If the current active element is the last element, meaning we're at the end trying to go further, then we call focus on the first element and prevent default.
[00:07:02] So yeah, so we can kind of see this, I have one thing I like about tab trapping is that it basically combines everything that we've been talking about so far. So, it's like listening to certain key codes. It involves active element. It involves calling .focus, all sorts of things like that.
[00:07:20] Again, I would recommend if you're doing this in production to not hard-code the first and last classes, but just grab a list of all queryable elements. But yeah, other than that, that's pretty straightforward.
>> I was just gonna ask about the conditional with key code nine.
>> Yeah, that's a good call.
[00:07:35] That's just a browser discrepancy. So some browsers will send the key and some will only send the key code. So I think I have a feeling that I think key code might be safe across all browsers. But for this example I just wanted to, and no matter what we have, it's either key code or a key.
[00:07:53] Those are both equivalent to tab nine is the key code for tab. So yeah, I think this works pretty well. So if we go ahead and we save it, and we go back to my example here, and refresh the page. Now when I click on the tab trapping, and I start shifting or tabbing through, when I get to, I know it's a little hard to see.
[00:08:13] So, the focus ring is on dangerous action. I hit tab again, and it brings me to first name instead of going up to the browser. And if I Shift+Tab, it takes me back to dangerous action. So, like if I was holding tab on it, I just stay on the modal for all intents and purposes, I'm completely constrained to it.
[00:08:28] I thought I'm just having now is that, it might be nice to also add this X here as a tab-able button. If I had been thinking a little bit more, so folks can know to close the modal. Although another thing to keep in mind, and we talked earlier that a lot of users expect J and K to do next item, previous item is just sort of standard.
[00:08:49] Similarly, a lot of users expect the Escape key to close any modal. And so that's like another thing that I do a lot at work. I see modals that the Escape key doesn't close. Those are really hard to close, I mean, the only two ways that keyboard only user has to close a modal is if they're able to tab to the X.
[00:09:06] And if not, being able to hit escape to close it, so escape to close is really important. Again, most design systems will take care of all that stuff for you.