Transcript from the "Progressive Enhancement Solution" Lesson
[00:00:57] So I just hid the tabs, like if it's not interactive what are the tabs there for, really? Maybe you might need it for heading purposes to match the content but depending if the tabs are all in a row and the tab panels are all in a row then that will make sense.
[00:01:14] So depending on how your tab switcher is marked up, you might need to change that, but I just hid them all. And then the tab-content I have a display here just turning those so that all of them are back on. I did experiment playing with the target, the target selector in the browser, so that I think, yeah, I don't know if I actually [LAUGH] finished this.
[00:02:04] So find that element access its class list and remove no-js. And then I'm doing the scripting to actually bind this as a tab switcher. So going and finding the tabs using querySelector all, the tab panels, creating an array from the tabs. So when you use querySelector all, I don't know if anyone else has run into this, but it returns you a node list and not an array.
[00:02:29] Huge pain for a long time, and the quickest, easiest thing I found is to just convert it to an array with array.from. That requires support for array.from, you might need a poly fill or you can just use a for-loop and iterate over them too, but since I have Babel turned on here in Code pen, I just went for it.
[00:02:50] So then I iterate over these tabs and go and add a role of tab, the aria-controls that's a state, Aria control state, and I point it to each tab panel, so go and just grab the ID off of the tab panels. I'm removing these so to sort of help me out in dynamically binding these.
[00:03:36] The tab panels I'm going through each of those just since there's a one to one, there's three tabs, three tab panels. When I'm iterating over the tabs, I can go and add a role of tab panel to each one, and then I've got some code to go and get the current tab.
[00:03:53] So starting up here, store a variable of which tab index is the active one, I start at 0. I have a kind of reusable function here to get the reference from the tab panels, or sorry, the tabs. Each one has an href, this is were that target selector came in because the href of each tab.
[00:04:21] I believe these were bottoms originally and I converted them the links so that I could used that internal linking so that when I click on a link I send it to the ID that matches that href, the internal link. And so I can use that to get a reference between the tab and then its associated tab panel.
[00:04:42] Let's see, let's go back down to the bottom. So for each tab, each one has a click listener, because I'm sort of like progressively layering on top, I'm overriding what the link would normally do, and so I'm preventing its default action, and I'm using that to change the tab.
[00:05:00] So when I iterate over each tab I know which index it is cuz I'm iterating over a collection. I can go and add, I'm gonna change this to keyup based on Amy's great suggestions earlier. So I've got a keyup listener and I can change keyCode to key, I don't know, actually remember what the stream names are so you probably wanna change the deprecated key code to something more modern.
[00:05:25] [LAUGH] Just logging the event object when you interact with it you can go and play with that and that might come up a little bit layer in our testing section. But then I have these reusable functions of a prevArrowkeyHandler and a nextArrowkeyHandler and I pass it which tab index I'm currently on.
[00:05:43] So that way I can keep a reference of like which one was current last, and I can increment and decrement. So the prevArrowkeyHandler checks if the current index is greater than 0 cuz I don't wanna get an error trying to left arrow off the screen [LAUGH] somewhere it doesn't exist.
[00:06:00] So if the index is greater than 0 I can go and get the tab that matches the index to the left. And I will send focus to it, so that I'm in the right place. The changeTab function just goes and unsets the tabs each time, so it goes and removes an active CSS class, that's what changes the display, it changes the aria-selected state.
[00:06:45] And then for the currentTab I go and add aria-selected if true, give it an active class on both the tab and the tab panel. Set the currentTab index to the one that the handlers have decided is the one. So a little bit of like conditional logic to check that we're in bounds here.