Website Accessibility, v2

Active Element & Tab Trapping

Jon Kuperman

Jon Kuperman

Website Accessibility, v2

Check out a free preview of the full Website Accessibility, v2 course

The "Active Element & Tab Trapping" Lesson is part of the full, Website Accessibility, v2 course featured in this preview video. Here's what you'd learn in this lesson:

Jon discusses a DOM API called active element which returns the currently focused element and tab trapping to send users back to the first stored focused element when they reach the last focus element and walks through of how to use active element and tab trapping on a modal. A students question regarding the conditional with keyCode 9 is also covered in this segment.


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.

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.

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?

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.

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.

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.

It could be terrible. So, this is one that's pretty useful. Again, it's simple as just storing the element and then calling .focus on it later. This is the last kind of advanced technique that we're gonna talk about. And we'll just build through it together instead of doing it as an exercise cuz it's a little JavaScript heavy.

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.

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.

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.

And if they don't have vision, then they don't even have any indication that they've left the modal. So they're like kind of browsing the website when the modal is the only thing interactable. So the idea with tab trapping is a JavaScript technique where you grab the first tab-able element in a modal.

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.

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.

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.

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.

So when the button is clicked, we call 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.

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.

Learning like the JavaScript technique is not really the important thing, I just want people to be comfortable with the concept. So, what I did here is I hard-coded two things. So I hard-coded the class of first on this one, and the class of last on this one. A better way to do it would be to use that focusable library that I showed that has a big string.

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.

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.

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.

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.

So again, it gets a little bit messy, a lot of modals will do this for you if you're using bootstrap or some other JavaScript library. But I did kind of wanna give folks a chance to understand the concept, and then just see some of the code for a simple implementation of it.

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.

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.

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.

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.

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.

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.

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.

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.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now