Check out a free preview of the full Accessibility in JavaScript Applications course:
The "Coding an Accessible Dropdown" 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 begins coding a dropdown that is accessible via the keyboard, identifying ways that the original dropdown is not accessible. - https://github.com/marcysutton/js-a11y-workshop

Get Unlimited Access Now

Transcript from the "Coding an Accessible Dropdown" Lesson

[00:00:00]
>> Marcy Sutton: So in our application, the drop down demos page, there is an example of, a drop down. That is completely broken now, so that's fun. It doesn't work for everyone. It's equal opportunity and accessibility. So the idea here is it's really similar to what we saw on the slack interface.

[00:00:22] It only works with the mouse. We don't really need that version, we need the more accessible version. So let's go over to the code editor and start working on that. So a quick tour around our application, I'm gonna back out here. So at the root of this project, there's a number of Gatsby specific files, like Gatsby-node.

[00:00:44] Gatsby-config, Gatsby-browser will talk about Gatsby-browser a little bit later. His intro to Gatsby Course would cover a lot more of this. So I'm not going to cover a lot of that. But the source directory is the part that we mostly are concerned with. And in here, there are pages, templates.

[00:01:04] My slide deck is in here. The pages are probably like that and components, I think are the most relevant for the exercises if you wanna work in this project. So the drop down page is what Gatsby uses to generate the pages on the website. So just by having a drop-down page in here, it will create a route at the page called drop-down.

[00:01:31] I didn't have to do any routing or anything like that, it's all kind of handled by Gatsby. So on this page is where I can import components. So with a lot of this stuff, we can kind of spread the accessibility or inaccessibility around with components, and the reusable and multiple pages.

[00:01:48] So that's how these pages work, is that I have a bad drop down here. And then what will be a better drop down because it's always a in the pursuit of accessibility, it can always be better. So I'm gonna go over to my components. So we've got this, this drop down version, let's go scroll down.

[00:02:08] So in react, we have our logic and our templating all together. Which some people like, some people don't like. I like it a lot because it just cuts down my back and forth between files. And so this mouse version, I can look at it and see there's a span with an on click.

[00:02:29] So that's not focusable, that's our first problem number one. The items that it opens up are in a series of divs. So there's no nount for a screen reader of how many items are in this drop down, so that could be better. And it's doesn't really have any focus management or focus ability at all.

[00:02:48] So what I'm gonna do is go over to in the better directory is where, so I have like the bad examples that are what you shouldn't be doing. And then in the better folder is where the the fixing it area will go. So I'm just gonna start from a mostly clean slate.

[00:03:07] I've got this drop down. It's importing some CSS, so I've got SAS here actually. And what I like about this is I can write SAS, this project is importing it and converting it to regular CSS. And I personally really like using CSS files. CSS and JS, as I mentioned, is also really common.

[00:03:29] So there is some CSS here that, if I write elements that match these selectors, I can just skip the styling part and focus on the interaction part. So I'll keep that file open and this dropdown.js. And I'm gonna start by adding just the markup. Which is kind of my favorite part of writing a component.

[00:03:48] Is just like the freedom of writing HTML and not worrying about anything else. So I'm gonna create a button element for our activator. So the part of the widget that I'm gonna click on or focus on to open the thing. And I'm gonna make this dynamic by adding some activator text.

[00:04:07] I'm gonna give it an empty string as a default. Actually, let's call it droppeddown just in case, when this component is initialized, they don't pass in some text. I'm gonna do that. I'm also gonna pass some items because I need the items to come from the outside. I'm gonna initialize it with an empty array.

[00:04:28] And then in our button, I will do activator text. And in react, you put it this in between the curly braces and it will dynamically, so if I pass in some other label from the outside it will just pass it right into this spot. Okay, what else? So we've got our focus double button element.

[00:04:51] I'm gonna indicate that it, actually I'm gonna start with the list. So I've got the kind of control I'm gonna click on and I wanted to open some items. So I'm gonna create an unordered list and inside of the list I'm gonna add a number of items. So I've got that items array.

[00:05:10] If it's passing anything in I can integrate on them with the map function and say, item in index says arguments to the map function. This is ES6, which Gatsby is gonna convert into ES5 JavaScript. So I can use the most modern in JavaScript here and not really worry about backwards competitors ability which is nice.

[00:05:32] So if I'm iterating over these items, i can return a list item for each one. In react, we need to add a key. So I'm actually gonna use that index from the map, since it's already giving me and something that I can iterate on. So I've got this list item, inside of it, I'm actually adding a list of links.

[00:05:53] So my drop down will have a list of links that I can reach with the tab key. And the structure of these items. It's so it's an array of objects and each object would have text and a URL. So I'm just gonna count on that being here and say, item.url.

[00:06:11] And then inside of the link, I will say item.txt. So I've got my button and my items. And I want to indicate that this button is going to open these items. So I'm gonna say aria-haspopup, which is useful marker to put on things like drop down trigger elements.

[00:06:34] Because in a screen reader it will say, like there's something associated with this button. Like, there's a pop up here. So that means, when I click this thing, there's something associated with it that I'm gonna interact with. So that's why I'm adding this attribute. So aria-haspopup, I'm gonna do aria-controls which has mixed support.

[00:06:56] But what this will, it will bind with the idea attribute of another element to create a relationship using aria. So this is some accessibility information that we can plug in here. I'm just gonna hard code this for now, just to start and give that, I'm gonna give this list an ID of dropdown1.

[00:07:16] Just cuz I'm in a server prototyping phase of this, so I'm gonna say ID of dropdown1. So that will add that relationship between the button and the unordered list. This button also needs some interaction, so I'm gonna give it an on click. And then I'm gonna to write a click handler function here in a second.

[00:07:35] Let's go up here in the top. So the way I've set up this component, it's a stateless functional component. So it doesn't have things like create class and in react to things like life-cycle callback methods. I really love this way of working because I can just focus on my markup in JSX here and then I can just write some functions, and it's a lot simpler.

[00:07:58] So I'm gonna write a conts clickHandler, so write this function. Using an arrow function, I can pass an event attribute or argument. So I've got this clickHandler, now that's defined, so that's a good start. Let's see, I am going to use some reactive API. So useState, useRef and useEffect are really useful.

[00:08:26] And since I've structured my component like this, the stateless Functional Component I can use these react hooks. And It's been a game changer for me. So let's go see what those look like. Reps are really useful in focus management in react because you can mark an element as important for focus, like this element I want to focus on.

[00:08:48] It keeps you from having to try and go find a DOM element, like the React way is to use the API's, use things like refs. So I'm gonna create a ref. Let's call it activatorRef. ActivatorRef, and I'll say useRef and just pass it a null argument. And that is calling this React useRef that I'm pulling out of the react package.

[00:09:17] Let's see, I'm gonna make another ref for the the list. So that when I open it I can send focus into it. So let's say dropdownListRef and I like putting the name ref in the variable just so that I know that, that's what that corresponds to. So we'll say useRef, null.

[00:09:36] I'm also going to handle some state. So I need to handle like the component needs to be open, and closed. So let's say const, I'm gonna create like an assign, an array here, and say isOpen. And this is some magic of the useState, I can put the thing I want to toggle which is open and then a function to set it.

[00:09:57] And the [LAUGH] React hook for this for useState just does it, it's awesome. So I could say useState, and if I wanted to have a particular state at first, maybe it's not open to begin with, that's what I would expect to see user. So I'm gonna say useState false, and I'm gonna go bind this ref on the button that is supposed to refer to with ref equals.

[00:10:22] And I'll say activateRef, and the drop down list, I'm gonna add the drop downlistRef. Let's see, so what else do I need? I'm gonna add a className. If we go back to our CSS. I've got some CSS written already for drop down activator, and then react. Because class is a reserve word in react in particular.

[00:10:53] For us the class and name attribute, that's how to keep react happy. But it will compile to the class at class attribute when your HTML is all complete and beautiful. So we'll say dropdown- activator, is that what I call it? And I can switch between tabs and VS code with option command left and right arrows.

[00:11:15] That's something I use quite a bit. Okay, so our button is looking pretty good. I'm gonna go add a className to the list. I think it's dropdownList. Item list, I knew that didn't seem very consistent with my camel casing. And things, item list