Check out a free preview of the full Accessibility in JavaScript Applications course:
The "Skip Links Exercise" Lesson is part of the full, Accessibility in JavaScript Applications course featured in this preview video. Here's what you'd learn in this lesson:

Marcy instructs students to add focus handling to either a React or a vanilla.js skip link.

Get Unlimited Access Now

Transcript from the "Skip Links Exercise" Lesson

[00:00:00]
>> Marcy Sutton: So that should be it for this custom route heading. And now I'm gonna go implement it. So I've still got an import here. It's looking for it in the better directory, so we're in the right spot. It's grayed out because I haven't actually referenced it yet. But I'm just gonna grab that component name.

[00:00:22] And I'm going to change this h2 to a route target heading component. I'm going to pass in a level of two. So it'll give me that h2. And a quick note about headings is that we want to start with h1 on a page and go in order. So the h1 on our app is this top-level Accessibility in JavaScript Applications.

[00:00:43] Sometimes you wanna change the h1 to be the name of the page. You can play with the heading levels a little bit just I think the most important thing is that they go in order so that you don't skip levels. So I'm not skipping straight to h2, I already have an h1 elsewhere.

[00:01:00] So I've got that. The other prop I need to pass in is target id. And I'm just gonna say navigation and if we go. I think I need the, back here in my site Chrome directory I have a navigation snippet. So what's nice about working with React components is you can break up different parts of your site Chrome into different components.

[00:01:24] They're reusable but also you can just focus on that one part of your site or that one part of your application. And this is where my navigation lives. And there is an id of navigation here. I've also got a visually hidden heading here in the nav section. So in that left sidebar there is a heading here that says Navigation.

[00:01:44] But the part that I really want to focus on are these Demos. If I am coming from the Dropdown link here in the left and I want to send focus into it's matching content and then I want to skip back. I think the most appropriate place is to focus on these links where I came from.

[00:02:02] So that's why I am putting the id right here, so navigation that will match this use case. So I'm actually going to copy this because we need this on all of our pages. I've just used h2s here. I'm going to go change these real quick so that when I'm clicking around, they match and it won't matter what page I'm on.

[00:02:25] So I'm going to change all these. And hopefully we can just automate this stuff so it's easier and you don't really have to think about it but for now this will work. I mean this is how frameworks get made [LAUGH]. We prototype it, we see if it works, we get more user testing which is something I'm doing and then we see how can we make that easier for everyone.

[00:02:45] So RouteTargetHeading, and you can honestly call this whatever you want. Naming things is one of the hardest things in computer science. So, maybe the name will change. Maybe it makes sense to me and no one else. I think I've got two more here. I kept the imports in there so, it should be fine.

[00:03:06] The semantics page is an example for you all to use later. RouteTargetHeading is not fine. Okay, so I do need to import that somewhere. Let's see, which one was complaining, the index page. So I'm just going to paste this import, so it knows where to find that component.

[00:03:27] So now, if I hover here, I've got this little anchor thing that shows up. It looks kinda funky because there's a caret and an underline, so I'm actually gonna go turn off the underline.
>> Marcy Sutton: For this case it's an interactive thing. I really recommend keeping underlines on for regular text links.

[00:03:47] This is sort of a special case. So I'm going to say, text-decoration:none for this one little interactive thing. And probably I would use it like a more graceful arrow, but that's what I had [LAUGH] off the top of my head. Okay, so I think the other part that I need to hook up is back in gatsby-browser.

[00:04:10] So I guess let's go. What I'm going to do here. So at this level this API method doesn't really. I don't really have insight into what's inside my application and frankly I don't really want to know. I just want to go look on the page and see, is there a skip link kind of like the one that I'm looking for.

[00:04:28] I'm just gonna write it like that if, let's go see. I'm gonna do, set a variable and call it skipLink. And I'm just going to go look for it, document.queryselector. And it was called routeSkipLink was the CSS class that I added in here, routeSkipLink. So if there's a skip link on the page, I don't want to error out if there isn't one.

[00:04:55] And if there isn't one, it'll fall back to Reach Router doing some routing focus handling for us. But if there is a skip link, I'm gonna say skipLink.focus. And so this will go look for that component, in the event that there is a previous location because we've navigated.

[00:05:14] That'll be null on the first load of a page because you're just getting there, there isn't a previous location. So now if I use. Let's go see, I have an error. And by the way, if you see this Unchecked runtime.lasterror message in the devtools, I see that all over the web.

[00:05:35] It might be from a browser extension or something. It doesn't actually have anything to do with this application. So don't worry about that. So, I don't think I got my conditional right here. So I'm actually gonna do a little bit of logging and say, console.log(location, prevlocation). And we'll just go make sure that this method is working.

[00:05:56] So yeah, we've got a location and null here for when there is a different one. I was on the drop-down page already. I think maybe some styling to indicate to me that that's the page I'm on would have helped. So it's actually working because this is showing our little route skip link.

[00:06:20] So I'm gonna do that with the keyboard. I'm gonna close the devtools. And that was our focus outline on the navigation. So it's actually working. So I can go back and forth. It's working better than kicking me all the way back to the top of the application. So I'm pretty happy with that.

[00:06:39] I can go on to one of these links with the keyboard, hit the Enter key, it sends my focus to a skip link that it doesn't take up much space on the screen. I could opt to style that however I want. I can make it look like an icon button and give it an accessible name.

[00:06:55] I could make it look like an actual skip link and say skip to navigation. So there's some subjectivity involved with the design but it functionally serves purposes. We're not just sending focus to this wrapper element and then being like, all right, you're on your own. Go tab around and figure out where you are.

[00:07:16] This link is actually useful. Like it serves a purpose. And so through research, I found that that just made a lot more sense. As for where we skip back to, we could play with that a little bit. Like, I'm sending focus back to the wrapper element of the nav, maybe I should send it back to the link I came from.

[00:07:35] That's an improvement that we could make potentially. But that's how I would build this component. I guess one more thing we should look at is the accessible name of this, just to make sure that we've got that working. So I'm focused on this in the devtools. I'm going to go over the Accessibility Inspector, and it says, skip to navigation.

[00:07:56] So the ARIA label is stomping over the contents of that pseudo element. Because ARIA label on the parent will take preference over whatever's inside of it. So something good to know about that and I can see in this Accessibility inspector how the accessible name calculation is like what's winning, if I have multiple things, trying to like give it a name.

[00:08:19] I love this tool because it will show me which one wins. That can get a little tricky sometimes. And so I love that it shows what's crossed out, and what's actually going to be exposed to assistive technology.