Accessibility in JavaScript Applications Accessibility in JavaScript Applications

Coding a Skip Link: Creating the Component

Check out a free preview of the full Accessibility in JavaScript Applications course:
The "Coding a Skip Link: Creating the Component" 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 uses React and CSS in JS to create a skip link component for the course website, walking through accessibility choices along the way. - https://github.com/marcysutton/js-a11y-workshop

Get Unlimited Access Now

Transcript from the "Coding a Skip Link: Creating the Component" Lesson

[00:00:00]
>> Marcy Sutton: So to get started, I'm gonna open up Gatsby browser, which every Gatsby site, you have the ability to use this, it's not required. But this gives you some API handles on what Gatsby's doing on the client side. There's also a Gatsby node which is stuff for like building your content out.

[00:00:21] There's another file that I don't have here but I could add is Gatsby-ssr.js, and that's to do special things for the server rendered part. We're focused on the browser client rendering part and in their APIs, there is an on route update function and it gives me a handle on the location that I'm at now.

[00:00:44] So the route changed, and it will tell me the previous location. So if I click a link and I'm going from page to page, I can tell whether I'm loading a page like fresh. So if I go straight to a page, I probably don't want to manage focus but if the users clicking links within the site, that's when I wanna manage their focus.

[00:01:02] So I'm gonna use this on route update. And if I've got, if location. So I wanna check if the location, if previous location exists, so in on the first view of a web page, previous location is not going to be there. So prevLocation, that means that exists. I'm gonna add a little bit of logic here.

[00:01:33] The other parts of this that I'm gonna work on include, so in the components for this application there's the bad and better examples. And then there's this directory called site-chrome and that's where everything that's like the header of my application, the header of my slides, those live over here.

[00:01:51] So I'm going to go pull up my header. And that's where in the application, I have this skip to main link. Let's see what else do I want to pull up. Because that'll probably change. I want that skip to main to go to this link that I'm going to create.

[00:02:07] So I'm gonna keep that open. I'm gonna create a new component. And I'm gonna put it I actually have the file here and it's got stuff in it. So let's clear it out and I'm gonna do import react from React. I'm going to use some CSS and JS here for this because I want this component to be self contained.

[00:02:31] I don't want people who are consuming it to also have to grab a CSS file. So from the component standpoint, I think CSS and JS is a good choice for this. So I'm going to import CSS from emotion core, which is a library I already have installed in this application.

[00:02:47] That'll allow me to write CSS the way that I want in this file, and it'll just be applied to whatever we write. So I'm gonna write some styles here and I can call this CSS method. And I pass it a template literal. So these till the characters in between them, I can write multi line CSS.

[00:03:10] So, I'm gonna go apply some stuff. I have the headings that, let's go back and look at the site, so this heading right here. I want to apply, insert a link into the heading. So if I'm gonna position to absolute off to the side, I need to wrap the parent element with position relative.

[00:03:30] So I'm gonna add this through my component and I'll say position relative. Let's see what else my route skip link.
>> Marcy Sutton: I'm gonna add some CSS for this. So that'll be positioned absolute because I want it to be just off to the side of this heading. I'm going to give it a display of inline block.

[00:03:55] I think with position absolute display block might be fine, but I'll leave it. I'm going to say, margin left, I'm going to give it a negative margin so that it'll be offset to the left. And that's something like the style of where this link gets placed, you might want to play around with a little bit just depending on your layout and your design.

[00:04:14] I think there is a way to make this pleasing to people so it doesn't get turned off, [LAUGH] but you might need to play around with it a little. By default, I'm gonna make this opacity zero. So our styling that we heard earlier. That way, this link is rendered, but when I focus on it, I'm going to change it so routeSkipLink.

[00:04:36] If I focus on it, I'm also gonna make this work on hover. So if I say routeSkipLink:hover, then I can change it to opacity 1. And so that's, this routeSkipLink is going to be an anchor. And what I'm really concerned about is, I'm gonna add a little icon.

[00:04:56] So in this case, it's a skip link, I'm making a design choice here to show an arrow, instead of the word, skip to navigation. I'm gonna add a label to it, but this is where it, you can change it depending on what your design team or you decide.

[00:05:13] So far this, I am going to add a pseudo element for the before pseudo. And that's how I'm going to insert a character and I don't have the key codes for an arrow handy. So I'm just going to add a left caret. And I'm gonna give this display of block.

[00:05:33] So the display block and the content property of a pseudo element will get it to show up and it's a pretty useful tool. So we got some styling, I'm gonna go add the component for this. So I'm gonna call this a RouteHeading, so in my pages. And this is where the pages are gonna start to come into play.

[00:05:55] So if I go look at each of these demos, right now I'm just using a native heading element and each to. This is where I could use a custom component that will insert the skip link for me. So that's where I'm gonna consume this component that I'm writing.

[00:06:09] And I'm gonna call it a route heading. Cuz it's a special kind of heading that's going to add this skip link and take focus when the conditions are right. So to make it super reusable, I'm going to pass in the level. Because I don't know where this is gonna get used.

[00:06:23] It might be in H1, it might be in H3. So I need to make that heading level configurable. So I'm going to say level and just start with one as a default value. I need to know what skip link target I want to send that link back to.

[00:06:39] So when I land on a skip link, it's going to take me somewhere with just a regular internal link in HTML. And I'm going to pass through the child elements. So this is a component wrapper. If I have other things in my heading, I want to preserve those.

[00:06:54] So I'm going to pass those through as child props. And to get this component set up, I'm going to create this dynamic heading in here using these template literals. And I'm going to create a dynamic component with a dynamic element name so I can pass this level in here.

[00:07:16] So it's a little bit of magic. The heading, so it'll turn into H plus whatever, like H1, H2, H3. This is just making a more reusable component here. And that's all I'm going to do for some of this setup. Now I'm going to return a heading component that we're creating with the level that gets passed in.

[00:07:37] I'm gonna apply the styles that I set up about with the CSS property and just pass the styles object. I'm gonna give it a class name of route skip heading cuz that's what I called this up here. So to get that heading to be positioned relative and these are handles that I have because I'm going to be using this custom component instead of a raw heading.

[00:08:03] It'll still give me an actual HTML heading but I'm going to work around some of that stuff. There we go. Okay, so inside of this heading, this is gonna give me that H2 back that I needed to begin with. This is where my custom component's gonna come in, and that target ID that I'm passing in.

[00:08:24] So I am going to go find, I need a template literal here. So I can add the string of the hash character. So that, if you use an internal link and you match an ID of an element with an HF, this will create that internal link. So I can actually link to any element on a page by matching its ID.

[00:08:46] I'm going to use that here for my skip link. And then I'm gonna pass in, the target ID. So this working is going to depend on me passing in a valid I.D.. And this is where if we end up solving this at the framework level, maybe that could be more dynamic, maybe it could look for nearby content.

[00:09:04] See where you came from like, maybe this could get fancier later on but for the first version, think of this as a prototype, I'm just gonna go for it. So I've got the href, that will make it focusable, and it'll give me the skip link action, which who doesn't love a good skip link?

[00:09:21] I'm gonna give this an ID just to create one. This is where it could get more dynamic later on but the way that these pages render, there's only gonna be one of these per page. So having a single idea of skip link in this case is gonna be fine.

[00:09:38] I'm gonna give it a class name to match the route skip link CSS that we wrote above. And then I'm gonna give it an aria label. So that I'm rendering a little arrow icon. I need to give it some sort of an accessible name so that screen readers when they land on it, they know what it does.

[00:09:57] And this I'm gonna pass in skip two and again because we're prototyping, I'm just gonna put in the target ID, so in this case, it'll be navigation. I'm just gonna use that cuz I'm skipping back to navigation. It's quick and dirty it'll work. And then inside of the link, there won't be any contents because we're using aria label and CSS.

[00:10:23] But I do want to pass in the child props. So if that heading, say the the H2 that I'm replacing, like maybe it had a span in it or something for like styling purposes. That's where passing the children and would be important. And then I'm going to export default route heading, just so that I can get this component to be something I can actually use.

[00:10:45] Make it part of my JavaScript bundle.