Building Accessible React Apps - Live Workshop 2019-11-14 Part 3

Erin Doyle
InstructorErin Doyle
Share this video with your friends

Social Share Links

Send Tweet
Published 5 years ago
Updated 4 years ago

Building Accessible React Apps with Erin Doyle

Instructor: [00:01] I did realize a couple of things while we were on break. While I was talking about that using react-intl, I realized I talked with my hands a lot, I probably should have coded it out so it was clear what I was talking about.

[00:15] Here's an example, real quick, of what I would recommend doing. If you're not familiar with react-intl, just know that this is going to go get me a translated message based on a set lookout.

[00:33] I call that. I get my translated message, set it to variable. I would put that here in the span that I already have with an ID on it as opposed to using formatted message, because formatted message, behind the scenes is actually going to be putting a span around the message. We would have ended up with span.

[01:09] Oops. Be careful of that, it's going to render down to a span, which is wrapped with a span. That just seems extraneous. We just plopped our message in there instead of the extra wrapping. That's what I was trying to describe with my hands.

[01:32] The other thing I noticed in chat, Jess of Chamber points out that there are new issue on five elements, which is exciting. I would just suggest, go check them out and then go do a little research to make sure they're supported well be browsers.

[01:50] Maybe do a little testing to make sure they behaved the way they should for the screen reader and whatnot. That is definitely exciting. I'm going to check those out myself. I think we are ready to get back to it. Sorry. I've got too many little windows covering up all my stuff. OK.

[02:19] We should be on tag v3.06. Now we're going to talk about images. All images should have text alternatives that describe the information or function represented by them, so that they are read appropriately to folks that can't see them. Most people probably are already familiar with the alt attribute on the image elements.

[02:54] All image elements should have an alt attribute provided. When it's not provided, the fallback for a screen reader will be to read the filename for the image. That's not just not useful at all.

[03:08] We can avoid using words like image picture icon to describe the image because the screen reader's already going to describe it as an image. That's redundant to say blah image image. Depending on what purpose the image serves is going to change what we put in that alt attribute.

[03:34] Some images that are completely decorative, they're not actually providing more functionality or information around the page. We can just go ahead and hide those from the screen reader and it won't read them at all or read their presence at all. We do that by providing an empty value, but we want to make sure it's not a space, it's just an empty string. Be clear about that.

[04:08] The different kinds of images that we may have. First, we have informative images. These are images that graphically represent concepts and information. Here in this example, this image is showing us that this is a phone number. This image is indicating that this is a fax number. We want to include a short description conveying the essential information presented by the image.

[04:39] For this example with these two images, our alt text could be telephone and it's going to proceed the number. When this is read, it's going to say telephone image and then read the number and then fax image and read the number.

[04:57] Here is an example of an image that provides instructions. We definitely...

Audience Member: [05:06] Can I ask you a question about the empty alt?

Instructor: [05:10] Yap.

Audience Member: [05:11] Is there a difference between having an empty alt or a role presentation on the image?

Instructor: [05:19] I can't remember exactly how that works and if it's consistent across all screen readers, so that might be something you'd need to look up. Definitely the concept is the same. We want to hide the existence of this element from the assistive technology APIs tree.

[05:41] It creates a tree of the elements in the DOM that it's going to read and so by putting that empty ALT attribute, it takes it out of that just like role presentation would. Then result is the same, but I don't know without some research or testing if it actually behaves exactly the same or not. Definitely a good question, something to check out.

[06:10] In this example, this image is actually describing how to do something. We definitely need to make sure that's conveyed with the user. Our ALT text would be to textually describe the instructions that we're seeing in the image.

[06:31] All right. Functional images, so these are images that are used as things like buttons or links or other interactive elements. When you interact with them, they actually have a function. They actually will do something. We need to make sure the user is communicated to what is going to happen if they interact with that image.

[06:58] In this example, we've got a little printer image and it's a link. When you click on it or when you select it with a keyboard, it's going to print. We want to make sure that the ALT text actually describes that behavior.

[07:20] Here is an example where there is another image embedded in a link. We already have text that describes what the link does, but the image gives a little more context. It's not just a normal link. We're actually going to open it in any window. That's what we say here.

[07:43] There are images of text, which really we don't recommend. Sometimes you need to have text in your image. If you can, maybe try to convey that with actual text using CSS to give it the design you want. If that's not an option and you really have to have text in an image, then the ALT should have that exact same text, so that that is what's right to the user.

[08:12] They're not missing half of the message that decided these are my half. Here in this example, this is a whole image with text in it. That ALT would just be that exact same message.

[08:29] Finally, we have decorative images. They don't add anything. They're not useful. They're not giving any more information. They're not functional. They're just there to make the page prettier or whatever. They're not helpful for those can't see it. This is an example where we would want to give that empty ALT attribute.

[08:57] We're going to look at the movie browse page where we have all those movie posters. There is an ALT attribute provided for them, but it's not helpful. It's like sometimes we can provide more harm by not doing things in a certain way than if we didn't do them at all. Let's secure this.

Voiceover: [09:34] You are currently on the main movie image. You are currently on an image. At movie image. You currently on an image. [inaudible] movie image. You are currently on an image. Voice over off.

Instructor: [09:51] The ALT attribute for each of those images is movie. It says, "Movie image." We don't know which movie it is and that's just not really helpful to hear movie image over and over again. It's extraneous information.

[10:08] Let's see. I shouldn't be doing that, because I'm pretty sure we even an ALT prop. Right there, movie. Let me go ahead and show you, bit by bit, the different options we have, and how it behaves. If we remove the attribute altogether, that's when our linter is going to complain.

[10:47] If we do npm run lint again, it's going to go ahead and tell us, "All image elements must have an alt prop." Let's listen to what happens in voiceover when we do that. Wait, that wasn't it. I went to the wrong one. Nope. Too much scrolling. Here we go. No alt.

Voiceover: [11:36] Main. You current visited "Inception" JPG image. At the end direct add a "Gladiator" JPEG image. Add "Raiders_of_the_Lost_Ark" JPG image. Director, add "Mission_Impossible_Fallout" JPG image. You are currently on an image. Voiceover off.

Instructor: [12:02] That's pretty off-putting, especially the Raiders of the Lost Ark example. A lot of times, file names are even less descriptive than these examples. It might be a whole bunch of garbage. The user has no idea what that is. It's not helpful at all.

[12:20] We definitely need to have the attribute. It needs to exist. Now, let's do what happens when we supply empty. Let's at least check our linter and make sure it's happier. It is. It's OK with empty, because there are reasons for doing that. It's a completely legitimate approach. Here's what that sounds like.

Voiceover: [13:01] You are currently on the main. Current visiting adding level 2 for a page of direct add in. Adding level 2 for items. Gladiator. Adding level 2 for items, Raiders of the Lost Ark. Director, adding level 2 for items. Mission Impossible, Fallout. Voiceover off.

Instructor: [13:22] Hopefully, you notice that the cursor never went to the image, and it never read the existence of the image, which for this example, may be fine. Maybe those images aren't actually adding anything useful. Maybe they are descriptive or decorative only. That would be a fine approach if we chose to have those be skipped.

[13:47] We're still going to show what happens when we give it something more useful. In the movie component, we have the name of the movie available to us. There's the name of the movie. Whoops. Did that wrong. Movie poster.

[14:26] Real quick. Let's check the linter again. I'm sure it's happy with that, but we always want to keep iteratively testing. Yep, it's good. Then let's hear what it sounds like in voiceover.

Voiceover: [14:49] Main. The "Inception" movie poster image. Direct add in "Gladiator" movie poster image. Direct add "Raiders of the Lost Ark" movie poster image. Director add "Mission Impossible, Fallout" movie poster image. You are currently on an image. Voiceover off.

Instructor: [15:15] Again, good or bad, maybe we should just have those skipped altogether. There's an example of providing a description of the image that is actually more helpful. That's images for us. Let's jump to tag. 4.00Let's talk about color contrast.

[16:01] When the contrast between the foreground and background colors...Foreground is going to be things like text or borders, anything that is in front of another color. Foreground versus background. Any time that the ratio of the contrast between those is not sufficient enough, it could be really hard to distinguish things like outlines, borders, edges, details, and text, can be hard to read.

[16:33] This can impact anybody, whether you have a vision, disability, or impairment, or not. This might impact you when you're outside and you're looking at something on your phone, or the lighting's just not good where you're at, or as you age, and your vision deteriorates.

[16:56] A lot of these are things that impact anyone and everyone, but color contrast definitely does. You may have found that there are a number of things on this site as it is right now that are hard to see. It's definitely important for everybody.

[17:16] Here's an example of different contrast ratios. Again, this is the difference between the foreground and background color, is what that ratio represents. 1.6 to 1, it's pretty hard to read. It gets a little better at 3.5, but it's still a little fuzzy. After that, it's pretty decent. Up here, it's great. It's crisp and clear.

[17:46] That just gives you an example of how increasing that ratio really makes a difference. The Web Accessibility in Mind group, they recommend for WCAG, that's W-C-A-G, which I'm having a brain fog off the top of my head what that stands for, but they've put together the standards in WCAG 2.0or 2.1 that have three levels. Single-A, double-A, and triple-A.

[18:23] To meet the double-A minimum acceptable contrast ratio for text, it needs to be 4.5:1. Here's the example, 3.5. It's not quite there. 4.5:1 is what is recommended.

[18:42] An exception is made for that. It can go down a little bit when text is about 120 to 150 percent larger than the default body text. As text gets bigger, it gets easier to read. That requirement is not as strict when it's larger text. That goes down to 3:1 if it's 120 to 150 percent larger.

[19:08] These numbers were chosen because they compensate for the loss in contrast sensitivity, usually experienced by those with a vision loss equivalent to approximately 20/40 vision. 20/40 vision is about the vision acuity of most people around age 80.

[19:31] Again, this is something you may have seen fine, you may not have a disability, but as you age, you're going to be impacted by this. We all may be. That's where they came up with that 4.5:1.

[19:48] Another thing we want to be clear about is that we should not use color alone to convey meaning. If we want to show that something's in error and we change the color of something from green to red, or if something is highlighted and we just give it a change in color, some of these things can end up being missed by people who may have issues with color contrasts or color blindness.

[20:21] We have to add more to our design and more to our approach to convey that meaning. Here's another example, where you may have to go back and forth with a designer who has this really cool idea, but when you look at it in Windows high contrast mode or another high contrast tool, suddenly that really cool important thing is invisible and a user can't tell between one state and another.

[20:51] We need to, in addition to color, use things like typography, shapes, grids, spaces, borders, extra weight. All those different things in the designed toolbox to convey that message, whatever it is we're trying to show the user. You can't just use color.

[21:13] We've got some tools around how we can detect these things. We of course have axe. Axe is going to tell us, right there, elements must have sufficient color contrast. We have the same finding here in the console.

[21:33] Totally is going to annotate the areas where the ratio is not sufficient. What's cool about totally is that it'll give you some examples of what would be a better contrast ratio and you can preview those.

[21:51] If we turn the annotation off...It's very hard to see, but if you look at the username and password labels and I toggle preview on and off, it's a very subtle change because this ratio is not that far off. Sometimes, you only need to tweak your colors a little bit to get them to more acceptable levels.

[22:19] Sometimes, you may have to do a lot more than that. It's nice with this little suggestions it gives you. You might say, "OK. Let me just tweak this color to use that instead or this instead." It gives you some suggestions there.

[22:39] Also, if we look at cream dev tools and maybe I need to find something else to inspect. Let's see. If I look at my text color, so my foreground color, I can see right here what my contrast ratio is. This right here tells me it is not good.

[23:11] You expand this section and it will actually tell you which WCAG level it's not meeting. It tells you what the ratio needs to be in order to meet that level. This line right here is the line that you would need to cross to get to the next level.

[23:30] We're all the way up here and we'd have to cross here just to get to AA acceptance. You can see that's much more readable, but there's no way I can get to AAA based on again, the difference between my foreground and background colors based on that blue background.

[23:56] In fact, here's a preview right here. There's just no way that I can get a ratio that will meet AAA. This is when you might need to redesign your colors. Maybe this blue that I really like a lot is just not going to work well for people.

[24:13] I mean, especially for this help text. I got my glasses on and I can't read it. You could see that contrast ratio there, it's terrible. There's just no way to get to AAA. At this point, it's like, "OK. It's time to redesign our colors."

[24:34] That's one way to see that. There are lots of color contrast checking tools. I've got another one here. This is by level access, which is an accessibility auditing company. This is really cool. You can pick your foreground color, but I can't line up the pixels in my background color.

[25:02] It shows me the previous and you'll see...You can't barely see but it shows you three different levels of text. You can see as the text gets bigger, it's a little easier to see.

[25:15] It shows you a bunch of different samples of different colors and what those contrast ratios are. Basically, it doesn't have a suggestion for me to make this acceptable because it's so far off. This is a really great tool to use to pick different colors.

[25:40] If I changed this gray to white, I've got some options now and then if I ever respectively change the background blue, I've got some choices that would now put me in an acceptable ratio. It's still just AA though.

[25:59] This is a great way to tinker with the different hex values and get yourself to an acceptable level. This maybe what you go back to the designer with or maybe the designer has this tool themselves and they can mess with how do I get to acceptable levels that still match the design that I was looking for.

[26:20] One more tool that I want to show you that's cool is color.review. Same thing. You can grab your hex values from your app, you can plop them in here for your foreground and background. You've got the lines of which need to cross to meet the different guidelines. Like I said, there's tons of different tools that can help you with this part.

[26:50] I'm not really going to go into how I fixed all of my colors because we're not really doing CSS and styling here. My app is using bootstrap, so it's really just I've changed some bootstrap classes around. If we jump to tag v5.00we will, voila, see that in places where I needed to, I totally changed my palate.

[27:22] It's a lot easier to read now. I'm going to go through some screenshots, so some before and afters so you can really see the differences here. This is before. I want to show you the differences between a high contrast browser extension and Windows high contrast mode because like I said, Windows high contrast mode behaves very differently.

[27:55] All right. This is looking at our log in with the two different tools. We have a lot of problems with the browser extension. It can barely read any of the text. You can't really tell that the log in button is a button. With Windows high contrast mode, it's fine.

[28:15] On our wish list page, the same thing. Text is hard to read. We cannot even see this button. This is what I was saying earlier about until you test with these tools, you don't know that some things become completely invisible to users that are using the tools.

[28:33] Other things are OK here, but these buttons, it doesn't even exist. They don't know it's there. Then pretty much the same thing on the browse page, this button is invisible. One thing to notice is that over here in Windows high contrast mode, we can't tell which of these tabs is selected. Over here, it's clear.

[28:58] This is an example of where we're using color only to convey which of these tabs is selected and Windows high contrast mode just takes it out, it's gone. We have no idea. Now, we're going to do a before and after of each of the pages.

[29:22] Without any high contrast tool, this was hard to read for anybody. Now, everything is much more clear. Here's the browser extension high contrast mode, same thing. Now, we can read everything. When it's high contrast mode, no change.

[29:47] Here's the wish list, that button. We now can read this text, which is hard to read; it's now easier. This was just a bad color decision to begin with. Now, it's much better. Here's the high contrast browser extension now, that button is visible. Its text is easier to read. This text here is easier to read.

[30:18] We still have the problem on Windows high contrast mode with the selected tab, and same thing again. This button is much better. That's that. Finally...oops, jumping ahead. As I talked about, we can't use color alone to convey messages.

[30:49] Everything else is looking really great. If we were to run Axe and Totally again, we would see that all of the findings around our contrast ratios are fixed, which I can do here. See, it's gone. We have no more findings output to the console. Same thing here, and here.

[31:15] All of our tools are now reporting that things are good, which is great, but when you look at the Windows high contrast mode, and you can't tell which tab is selected, so we still have something else to fix.

[31:32] That's one of those things where we need to change the design. What I did was, I changed the design of the tabs to instead, look like vice versa, look like tabs instead of pills. Before, we were using a pill design. Now, we're switching to using a tab design.

[31:51] Again, not really going to go over the diff with you, because it's switching out some bootstrap stuff, but the idea is, sometimes we've got to go back to the designer and change the design. Here's what it should look like afterwards. Now we have tabs, and they are tabs. You can tell which one am I on, and what are the others.

[32:28] Now, let's uptake to v5.01. I'm just going to show you what that looks like over here. You can see the active tab. You can see your hover. Again, it's got to work for all of the different modes that people might be looking at it in.

[32:56] Focus management. This is the big one. The keyboard and screen reader users, as they are navigating through the site, they rely on the focus proceeding from one element to the next in a logical order, and that they don't get lost.

[33:17] Especially, the screen reader user who can't just see where they are on the page, they need to have a really predictable and logical order of movement throughout the page. They need to know, especially the keyboard only user, that when I am interacting with a given thing, I expect certain behavior.

[33:41] I'm expecting focus to move to logical places. Focus should begin at the first focusable element on the page. We really want to start at the top, and move in that top to bottom order. The first thing that makes sense to read as the context of where are you at on this page, and that logically makes sense.

[34:21] When content is added or removed from the DOM in response to a user-initiated event -- so they clicked on something. They selected something -- the focus should shift to the new content that has been added. Something expanded, we want to move to that thing.

[34:40] For instance, if we opened a modal, when we close that modal, we need to move back to where we just came from. There are rules around what is the expected place that my focus moves to, after I do a thing?

[34:57] We want to make sure the focus doesn't jump to the top of the page, the bottom of the page, or become completely lost after a user-fired event. If we're not managing the focus, sometimes it can just go back to the body.

[35:13] If it's not explicitly set on something, it'll go back to the body of the page. Then that can create an awkward experience for the screen-reader user, which I'll demonstrate shortly.

[35:28] We want to make sure our focus is on an area of the web page that has discernible text for screen reader users. We've already talked about how to label those things. We want to make sure that when we've moved focus to a given thing, that it is labeled in a way that that's described properly to the user. They know where am I at right now.

[35:53] The way we do this is by using rafs. Rafs is an attribute on an HTML element, that can be passed either a variable or a function callback to set a variable. The approach we take, how we actually implement that, can depend on which version of React we're using.

[36:16] Once we've set the rafs, it's like a pointer. Once we have that pointer saved to a variable, we can call the focus function on that variable. It will move focus to that element at the time we want it to.

[36:35] That could either be during a certain point in the component lifecycle. If we want to make sure that when a page renders, as you're moving to a new page, we might want...and the component did mal, to set the focus on the first thing on the page.

[36:54] Or, after a user-initiated event, once I've clicked on a button. On the on-click event, I want to make sure I am calling focus on that thing that I want the focus to move to. That's how we do it.

[37:09] I'm going to talk about, depending on which version of React you're using, how you approach [inaudible] . OK, so pre-16.3, you needed to use the callback approach. In a class-based component, you would have a variable. You would have a function that is passed an element and sets it to the variable.

[37:40] Just a sec. OK. On the element that you want to save the ref to, you would pass it that function. It would know that this attribute knows that if I was given a function I'm going to pass the pointer to myself.

[38:06] Then in the component did mal lifecycle event of this component, we're going to just make sure if we have this set, we have gotten our raf. It has been set. We're going to call focus on it.

[38:23] That works today. You can still use this approach. There are some times where you have to, especially if you are using maybe a third-party library. You're using components that are not your own. You may need to use this method, because you don't know what version of React that component might have been built with, and is expecting.

[38:47] This works. OK, here is the 16.3 and after approach. In fact, I'm going to put these side by side. They're both class-based components. In 16.3 React added this ability called "create raf." It's going to create this raf object.

[39:15] You would call that in your constructor, and set it to a variable. We already have the object. Instead of needing a callback to get it, we're going to pass it to the raf. Then very similarly, in our component did mal, also we're going to check if it exists, and call focus on it.

[39:35] The difference is -- and this is why if you're using something that's older, this is going to break -- is in the newer version it creates an object that has this current property on it. You call focus on current. If you're using something older, it's not going to have current.

[39:54] When you call focus on it, you're going to get an undefined error. That's something to watch out for. You can always check if I have current, or not, and call focus on the appropriate thing. Anyway, that's the difference between those two.

[40:14] Then, in 16.8, now that we have hooks, we have a useRaf option. If you were using a stateless functional component, not a class-based component, you could use the useRaf hook. It's similar to calling create raf. It's going to create this raf object.

[40:38] Same thing, you would just pass it to the raf attribute. Instead of having a componented mount, which you won't have in a functional stateless component, you could use a useEffect hook. Just check it. Do I have it? Do I have current? If so, call focus. That's the latest and greatest. Watch out for what version you're dealing with, and then use the appropriate approach.

[41:08] Just a little note about using useEffect with a raf, is if you have anything in your useEffect, if you've got any dependencies that you've identified that might cause that to not fire, then you may end up not calling focus when you wanted to.

[41:33] If you run into any kind of funky behavior where your focus isn't being called, or your raf's not being set, make sure you're clear on did you have any dependencies here that would cause this to not cause a re-render when you need it to? Something to watch out for, with that.

[41:53] Again, you don't have to use hooks. If that seems too complicated, or you end up with finicky, funky behavior that's not what you need, fall back to the previous version. It's fine.

[42:10] I'm going to show you right now, because we're not setting focus on anything at all, what happens from the screen reader perspective, when we navigate from one page to the next.

Voiceover: [42:34] You are currently on...Heading. Main. User name. User name. Edit D. Missed password. Password login button. Movie wish list. Web content. You are currently on a button. To click this button, press Control, Option, Space.

Instructor: [42:51] Right, I just want to stop that right there and make sure it's really clear. Our cursor is still focused on the button from the previous page. It's still saying, "You are currently on a button."

[43:02] We're not actually on that button at all, any more. We're no longer on that page. That's really confusing for the user, like, "What button? If I click this button, what's going to happen? I don't know. I don't even know that I'm on this page." That's very confusing.

Voiceover: [43:18] Heading level add a movie button. Movie wish list. Web content. You are currently on a button. To click this button, in movie, navigate, heading, back to wish list. Button, movie, wish list. Web content. You are currently on a button. To click this button, press Control, Option, Space. Voiceover off.

Instructor: [43:37] It did the same thing for each page. That cursor sort of stayed focused on the button from the page that we're not even on any more. It doesn't clearly read these are where they are, so that's terrible.

[43:51] If we're looking at where that focus is going, so let's go back to login. OK, so if I go ahead and hit the login button, we are now on the next page. If I look at document.active element, it's on the body. Because we didn't set the focus anywhere, it just defaults to the body.

[44:25] That's why the screen reader crusher doesn't know where to go next. It stays where it's at. If you are a keyword only user, I don't see the focus indicator anywhere. I'm going to have to hit Tab, and figure out where to start next.

[44:44] Eventually, you're like, "OK, that's where I am. That's fine." But it's definitely a much more detrimental experience for the screen reader user. I'm going to show you how this needs to be fixed. When we come to the wish list page, and we don't have any movies in our wish list, we want...My focus indicator is there, because I just left it there.

[45:18] If I go back again and just show you, it's nowhere. We want it to be here. We want to go ahead and right away tell the user, "You don't have any movies and you must just add some movies," instead of forcing them to kind of step through all of these elements.

[45:36] Again, this is where you really have to evaluate user experience. There's not a hard and fast, always do this rule, when it comes to focus. There are some things that have rules around focus, but definitely when it comes to navigating from one page to the next, you might need to just decide what is the experience I want to convey to the user?

[46:01] For this scenario, I think it makes sense to bring them to this statement right here, give them instructions so they can get started right away. If we check out tag v6.00all right. I'll show you what I did.

[46:28] I went ahead and set this variable to the add to movies link. I used create raf, because it's a stateful, class-based component. Because I'm on the latest version of React, I went with this approach.

[46:50] This is junk, sorry. To have a noisy diff. What's important here is right here. Unfortunately, because I'm using a third party library for this component, this linked component which comes from React router, I need to figure out like, "OK, how do I pass a raf down to or through that component?"

[47:14] You may find that some don't support it, which is unfortunate. This one thankfully does, and you've got to go look at the docs and see how to do this. For a linked component, if you use the inner raf attribute, React router will go ahead and pass that raf down to the underlying A tag href attribute.

[47:37] If I just pass it my raf object, that gets passed down. Then I have a componented mount. When the page loads, I want to check if my raf exists, if .current has been set to something, because otherwise it will be either nul or undefined. I'm going to call focus on it. That's how we do that.

[48:11] Then let me show you how we fix the wish list and browse pages. With this one, I decided...and again, I could have decided differently, but it made sense to me. I've actually done some research that I want to plug real quick.

[48:35] Let's see if I can Google it real quick. This would be accessibility. I bet I have this. I bet I put this in the references. Yeah. Thanks, Pass Me, for thinking of that. There was a study done by Marcy Sutton, who is a big leader and expert in the accessibility space.

[49:13] They worked with this user testing group called Fable Tech Labs, who have folks with disabilities using assistive technologies to do user testing. They tested a bunch of different approaches to where to set the focus as you navigate from one page to the next, and what works best for people.

[49:35] Please read the article. It's great. The TLDR is, it seemed like most people found it most useful for the focus to go to whatever the top level heading is for the next page. You may find some advice that says, "Go to the first interactive element."

[49:59] If we did that, we would jump to the tablist here. In my testing, I found that to be a little bit awkward. I hit the login button, and all of a sudden it says, "Action movies." But I think it makes a little more sense to say, "Browse movies," so I know that I'm on the page for browsing movies.

[50:23] That's what I decided to do. I did that. Now, let's look at the diff. This is a stateless functional component, so I went with using useRaf and useEffect. I'm calling my useRaf. I'm saving in a variable called [inaudible] . Here on my H1 I am sending the raf.

[50:57] You'll notice, if you can see it, I did have to disable ESLint on this line, because like I just said, ESLint, this rule is saying, "You can only put a tab index on interactive elements." Well, you can't focus an element that isn't focusable. The way to make an element focusable is by giving it a tab index of a positive number.

[51:26] I had to put a tab index on the H1 in order to make it focusable, but I feel like I've got a pretty darn good reason to do it, and I really do think, as we move forward, this rule in ESLint might be altered. I could also have added to my ESLint config an exception for H1s, because I really believe this is a more accessible experience.

[51:52] That's what I did. Now this, H1 has focusable. In my use effect, I am going to check. I'll explain due focus in a second. I'm going to check that my header raf is set and I'm going to call focus on it if so.

[52:08] I also added the option to pass into the header a do focus prop. There may be some times when I don't want the header to focus on the H1. Maybe in certain scenarios, I want the focus to go elsewhere. I want this to be something I can control.

[52:26] By passing in a Boolean do focus and always checking that in the use effect, I can control that behavior. The reason, the actual use case for when I would do that is on my wish list. The times that we don't have movies and we are focusing on the ads in movies link, then that's where we want the focus to go. We don't want the header to grab the focus.

[53:03] That's why right here, I have do focus set to whatever the result is of has movies, which I set based on if we have items in our wish list or not. That gives me that conditional behavior. If I don't have movies, focus here. If I do have movies, then focus on the header. We're going to listen to how voice-over handles that. There we go.

Voiceover: [53:46] Safari busy in user name. User and password, secure edit login button. Visited link, add some movies to your wish list now. Heading level one. Browse movies. Navigation. Back to wish list button. [inaudible] add inception. Add raiders of [inaudible] . Add mission revisited. The current. Back to wish list button.

[54:09] Heading level one. Movie wish list. Navigation. Add current watch, edit. Remove inception button. Remove raiders. Watch. Remove mission impossible. Add a movie button. Heading level one. Browse movies. Back to wish list button. Visited link. Add some movies to your wish list now. Voice over off.

Instructor: [54:28] Hopefully, you were able to follow that. When there were movies in the wish list and we navigate it to the wish list, it read the heading movie wish list. When we went to the browse page, it read the heading movie browse movies. When we removed all of our movies from the wish list and went back to the wish list, we focused on the add some movies link.

[54:58] If I go ahead and check out 6.01. Let's go back to the log in and watch my focus indicator to see where...We have to fill those in. No movies in my wish list, here's my focus. If I click on that, add a movie, back, there's my focus indicator. That's a much better experience. All right. We're getting close. Hang in there.

[55:49] All right. Live regions. At the very beginning, I talked a little bit about live regions. These are areas of the page that can have dynamic changes where content will either change or maybe be inserted or removed from the DOM.

[56:09] Of course, those are much more apparent to people who can actually see those changes. If not, they can't see them. We need to make sure that they are read to those using screen readers and whatnot. We can actually define the criteria around how those things are read and so these are called live regions.

[56:32] Some rules around defining live regions. A live region needs to first be present and usually empty in the DOM before changes are made to it. The browser and assistive technologies are aware of it. They know like, "Yes, I see that element. I see that it expects to get changes."

[56:53] If you dynamically added that element later, after the initial render...I'm talking about the whole element. If you add that whole thing later, or if you add the ARIA attributes defining it as a live region later, the browser's really not going to pick up that that's a live region and that it's going to get changes.

[57:15] You need to make sure it's present, it's defined appropriately before it changes. Once you've done that, any subsequent changes that meet the criteria that you've given to it, those will be announced. They'll be announced in a way that you define.

[57:37] We do this by either using distinct attributes, or there are even more advanced roles for more common widgets, so we'll go through those. This is not something that you have to memorize and always have off the top of your head. I have to look this stuff up every time.

[57:57] Just being aware of it knowing like, "I know what a live region is, what it's meant to do, let me go Google that to get more details," anytime you need to is really huge. Of the attributes that we have available, there's ARIA Live. When you put that on an element, you're saying this is a live region.

[58:20] You can define the priority with which updates are read. If it's off, it's not going to read updates. If it's set to play, the screen reader will wait until it's not reading anything else and then it will read that change. If you set it to assertive, whatever it's in the middle of reading, it will stop and it will read that change.

[58:44] Depending on what this thing is that's changing and how urgent it is will drive which one of these you choose to use. There are some things that if they're changing frequently and you choose assertive, that's going to be really annoying. You got to weigh that out. You've got to test it, see if it's...

[59:07] Is it telling you often enough? Is it telling you too often and decide which one to go with? If you supply ARIA atomic and true or false defines whether the screen reader should always read the entire region as a whole even if only part of it changes.

[59:32] If you have only changed some of the text for instance in a DIV that's set up as this live region, if you change only some of it should it read again, or should it expect you to replace the entire content before it reads again. That's what that does.

[59:51] Then ARIA relevant allows you to define what kinds of changes to read. Additions would be only read when new things are inserted into that element. Removals only read if something was removed from this element. Text only read text changes.

[60:12] Then all do all of these things. If you don't specify this at all, the default is going to be additions in text. Only when we add things and any text changes are going to be read.

[60:26] If you don't want to get down to this level of defining things, or if you're working on a widget that meet one of these roles that's available, then maybe you want to use a role for more common scenarios status if it's a status bar or an area of a screen that provides some kind of updated status.

[60:51] For alerts, if it's error or warning method that flashes on the screen. This is going to be more for page level errors. It's not something you'd want to use for form fields. It's a one thing that you want to draw these or its attention to.

[61:08] A progress bar, are you maybe uploading something and you want to show the user the progress of that upload? You can give it value min, value now, value max. If it's 0to 100 percent of that upload, and the value now will tell you where it's at between that range. It'll update, "We're at 5 percent, we're at 25 percent," and will continue to let the user know where they're at.

[61:40] These are examples of more common widgets. These values all set implicitly. When you add one of these roles, it's going to have very specific values of each of these set by the role. You can always use these attributes instead of a role, but if the role fits the behavior you're looking for, use the role.

[62:11] Our scenario here that we need to fix is our login form. We have error messages. When the fields are not filled out and the user goes to submit the form, we show error messages saying that those fields are required. We need to make sure that the user knows that they have validation errors that they need to address.

[62:34] This is a perfect use for a live region. Let's see what that's like.

Voiceover: [62:48] Voiceover in movie. End of username. Password. Passwords are case sensitive. Login button. You are currently on a button. To click this button, press control option space. Voiceover off.

Instructor: [63:03] There you saw, when we hit the login button and we had not filled out our required fields, we could see the error messages, but nothing is read to the screen reader user. They have no idea that they did anything wrong in that form. They don't know what they need to go change.

[63:20] They don't know that the form didn't submit and that they haven't moved past the login. That's a pretty terrible experience. A user would end up getting stuck on this page and not knowing how to get beyond it, because we're not telling them.

[63:39] We're going to look at fixing that. If we go to fixing the inputs in our login form, which are really in form input. Again, thankfully, we have this reusable component. Here is our error message. Let me show you how we supply this from the login.

[64:09] We always provide the error text, whether the field is invalid or not. We're always providing that value of what should be shown. In the form input, if we have it, which we always do, we're going to include that element in the DOM.

[64:30] Just a little implementation detail here. Because I use Bootstrap, by providing this class name, it knows to hide this element visually if the form is not invalid. It's not going to be hidden from the screen reader unless we do the right things, which we've already done here by not reading the ID if the form is non-valid.

[65:04] Bottom line, what I'm trying to describe is we always want this div to be in the DOM because it's going to be a live region that gets updates. We need to always render it and supply an ARIA Live attribute. We need to give it a value of polite. I will demonstrate why that is. By doing that, let's go back. Let's hear what it sounds like.

Voiceover: [65:47] Voice over in movie wish list. Web content banner. Username required. Edit text main. Password required. Secure edit text. Log in button. Please provide a username. Please provide a password.

[66:03] Username required. Invalid data. Edit text. Password required. Invalid data. Secure edit text. Log in button. You are current-, visited link. Add some movies to you wish list now. Voice over off.

Instructor: [66:22] We heard right there. As soon as we hit that log in button, it red both of the zero messages to us. We knew both of those fields needed fixing. If I had set that as ARIA Live assertive, what it actually will do is it will only read one of the two inputs because it's essentially interrupting itself.

[66:48] When we say assertive, we say, "Immediately read this thing that just changed," and so what it does is it immediately reads...I guess it starts reading the first one and then as soon as it sees that second one, has also changed. It interrupts itself from reading the first one and only reads the second one.

[67:09] We only end up hearing password is required and we don't end up hearing that we also missed the username. By setting it as polite, it will wait and it will read one at a time. That's really important. I had to discover that through testing.

[67:26] When I first put these together, I thought, "I want assertive because I want it to read that error message right away. I want to interrupt whatever it's doing and tell these there's an error." When I did that, that's where I discovered that it was actually interrupting itself.

[67:41] When I switched it to polite, I got the behavior I wanted. That's definitely a plug for...We need to actually test these things and see how they work. One other thing, or a couple other things I want to point out real quick that I changed for this.

[68:01] Let me show you the div. There's a couple other ARIA attributes that are really helpful, too -- ARIA required and ARIA invalid. These aren't specific to live regions. While we're making this fix, it felt relevant and so I want to point it out to you now. There are really helpful to add to fields to give more information on those fields.

[68:33] I'll play the video again in a second, but we actually get more context now that this field is required. When it's invalid, we hear that the field is invalid. If we didn't have those, it's not the end of the world. We've already told the user that there are these errors, but we'll now hear that the field is required before they even get to the log in button.

[69:00] As soon as they get to the field, they'll be told it's required. Now they don't have to make the mistake and then have to go fix it. We also provide that extra information, when the field is invalid, and they get to it. They're told it's invalid. It's continuing to give them that context.

[69:23] Let's listen to that one more time real quick, to hear how those are read.

Voiceover: [69:32] Voiceover in movie wish list. Web content banner. Username required. Edit text main. Password required. Secure edit text. Login button. Please provide a username. Please provide a password. Username required. Invalid data. Edit text. Password required. Invalid data. Secure edit text. Login button. You are current...

Instructor: [70:01] There it is. Thanks for hanging in there. We are at the last lesson. This one should be a short one. There is a concept in accessibility called either interactions patterns or design patterns. I've seen it called either of those. Our basic native elements or HTML elements, those are already pretty accessible.

[70:47] When we work on more complex widgets, and we have to combine various divs and whatnot, and we have to put in ARIA roles and a lot of attributes to describe, what is this thing, what's expected from it, what are its states, and then what is the keyboard behavior?

[71:09] When a keyboard user arrives at that widget, what keys can they expect to have what functionality? This needs to all be defined. You can find out there on a lot of great accessibility sites, design patterns for meeting these expectations.

[71:32] As I said, interactions with certain widgets need to be intuitive and predictable. Any events triggered by a mouse click needs to also be triggered via keyboard, so the keyboard-only users can interact with this widget in the same way. The state or status of the widget should always be clear to the user.

[71:55] If something is hidden, if something is expanded or collapsed, if it's selected, if it's checked, all of these things need to be read to a screen-reader user, for instance. Again, there are defined patterns for how we can meet these requirements for a given widget.

[72:17] To me, the de facto place to find this is w3.org has a whole listing of all sorts of widgets. I find that when I'm doing something new in the UI for an application that I haven't done before, and that the designer has given me what it is that I need to build, I'll go here, and I'll look at the definitions for these and figure out like, "OK, is what I'm trying to build this? What is the widget that I am trying to build?"

[72:53] I'll find the design pattern. I will follow the instructions. They give very clear, "When you do this, this is expected. You should apply these ARIA attributes. For these scenarios, they should have these values." It makes it very clear on what you need to do to make that widget accessible.

[73:25] For instance, we have on our browse and when we have movies on the wishlist. We have this tablist. That's a more complex widget that when a user arrives at it, they need to know what to expect.

[73:47] The keyboard-only user needs to know that when I click which keys, how am I going to navigate through this widget. The screen-reader user needs to hear context around these items in the tablist, and what are their states, which one is selected, things like that. The tablist design pattern defines all of these.

[74:12] The element that serves as the container for the tabs needs to have role tablist. Each element in the tablist needs to have a role of tab and would be children of the element that has the role tablist. Each element that contains the content panel for tab has the role tabpanel. When we change the tab, all of this content on the page changes respective to the selected tab.

[74:43] This is the tabpanel that's controlled by the selected tab. All of this functionality, it meets the tablist description. What I did is I went and found this, and I realized, "Yup, what I have here, this thing, it's a tablist. I want to implement this pattern."

[75:06] We also have labeling requirements. If the tablist has a visible label, which this does not, but say this had some sort of title here that said, "Movie genres," or, "Pick a movie genre," if we had something displayed that functions as a label, we would use aria-labelledby.

[75:27] If there was instructions picking movie genre, that would be our ARIA described by. Otherwise, we need to give it an ARIA label so that when the user gets here, it tells them what this is.

[75:43] Each element with role tab panel also has a aria-labelledby referring to the associated tab element. This whole tab panel itself is going to be labeled by the selected tab. We have that continual association. We always know what this thing is.

[76:08] All right. Each element that has role tab has a property. ARIA controls that associate it back to the tab panel. Once again, this tab has an ARIA controls that points it to this whole element holding the panel. Each active tab element has the state ARIA selected, which would be set to true. For all other tab elements, it's false.

[76:37] Again, this guy is going to have ARIA selected true. The rest of these are going to be false. Again, by setting all of these things, we give all that extra information to the screen reader. Then we have to control the focus. When the focus moves to the tablist, that parent container, we're going to move focus immediately to the active tab.

[77:04] If I cursored my way to this container, my focus would be immediately moved to this tab so that I don't have to find my way to it. When the parent contains the focus and...OK. Let me explain that better.

[77:27] As I'm navigating by a keyboard, when I hit tab from whatever the previous element is and I tab to the list to this container, if I hit tab again, I'm going to move to whatever the next widget is. Tab is not going to take me into this widget. It's going to take me from one widget to the next.

[77:55] This is something that I really had no idea about. I didn't know that keyboard only users had these expectations of certain keys had certain behavior. I thought, "Oh, you tab through everything." Right now, with the app broken, we do tab through the tablist.

[78:13] Really what's expected is when I hit tab and I come to the tablist, when I hit tab again, I should go out of the tablist to whatever the next focusable element is. That's what's expected. When I get to the tablist, left arrow should take me to the previous tabs. I should be going in this direction with left arrow. Right arrow should take me forward.

[78:40] Optionally, Home will take me to the first item in the list. End would take me to the last. If I'm here at the last and I hit the right arrow, I'm going to circle around to the front and then same thing with left arrow. It's like a circular list. OK, that's the tablist.

[79:07] Let's just jump real quick to some diffs if you would like to. I'm going to show you the exercises. This is something great to go through on your own later if you'd like to. Each exercise is associated with each of those requirements from the design pattern. Bit by bit, go add those things.

[79:36] We're going to jump straight to v.a.05 where it's all done. Actually, I'm going to show you div by div. First, I set at aria-label and roles to the appropriate places. We've got this tablist component already. We're going to pass in an aria-label to it. We're going to set that here on this parent container of the tab items. We're going to give it a role of tablist.

[80:25] Then up here is where we have our tab items. Each list item, we've given a role of tab. Then, basically, the movie browser and the movie wishlist are each passing in what the aria-label should be. It's going to say, when you get to the tablist, movie genres. Then the content of the page that changes has been given that role of tabpanel.

[81:04] 8.01 is where we add the aria-selected attribute based on which tab is selected. The tablist takes an active tab. It does this check like, is the ID the same as the active tab that was passed in? This is, to be clear, as we're mapping through our tablist.

[81:35] As it's iterating through each item in the tablist, it's going to check if the ID of this current tab equal to the active tab that were passed. If so, we're going to set aria-selected to whatever the result of that is, true or false.

[81:55] This active tab is maintained in state by the parent component. It's either the movie browser or the movie wish list. You can do that in a lot of different ways. The idea is, somewhere you're going to maintain and state, what is the active tab? That will inform which one of those should have aria-selected true.

[82:19] It does 02, we want to set that aria-controls attribute. We're going to dynamically use this ID for a number of different things. We're going to give each tab an ID using that, and appending tab. We're going to set the controls with that same value, and append panel.

[82:51] You can see how we end up using that for the panel. We've got that same value that we're using for the ID of the tab, and we're appending panel. I'm going to show you real quick some of these things, just so you can see them happening here.

[83:18] Our selected tab here is the comedy tab. We have aria-selected = true, aria-controls = "comedypanel." Our panel right here has an ID of comedypanel. You can see we've got our roles, as they should be, and our selected values. If I come out here...We aren't at the right checkout yet, but we change that. These selected values should change, as you can see.

[84:06] We needed to add an aria-labelledby to the tab panel native three. We're referring right back to that ID that's prepended with dash tab pointing back to it. We created another reusable component to hold that tab panel, so that we don't have to do the same things in both places. Finally, we add the keyboard interaction support.

[84:46] For the tablist, I had to reorganize some things. Needed to make this into a stateful class component. You could use hooks if you didn't want to switch to a class component. The idea is that, we now need to maintain state, and we now need to have life cycle events.

[85:11] We are storing that selected tab here in state, and we are setting the ref. We've got a variable for storing that ref for the selected tab. Here we have a callback to set that ref. Let's go down here. On the ref for our list item, if this is the selected tab, go ahead and set the selected ref.

[85:57] This is our callback function here, it's got the conditional in it. That gives us the ability to specifically set focus, based on the keyboard functionality, the keyboard behavior.

[86:14] We've made the tab focusable or not by adding this tab index. If it's the selected tab, give it a 0if it's not selected, give it a -1, because we don't want to be able to select it. We want to control which tab is selected, versus the other way around.

[86:36] We have our onclick and onkeydown handlers. Let's look at the onkeydown handler. We are looking for a left, right, home, and then enter and space bar for selecting. For each of these, we are going to do the appropriate thing call that one the design pattern. Go to first tab, go to last tab, go to previous tab, go to next tab.

[87:04] Each of these is basically calling select tab based on the number tab that we've moved our keys to. Then we are going to set the selected tab. When we set the selected tab, we are updating state here. When we update the state, our component data update is going to fire.

[87:41] Here's just the check that's like if we didn't change pages which is basically when we change tabs, we are doing a React router route. That's just implementation details. I chose to do that. If you noticed the RL it's actually routing for each of this. I didn't have to do it that way.

[88:06] Just as a safety, if we didn't actually change the tab, then don't call focus. If we did, then actually call focus on that tab. Hopefully that makes sense. Again, you want to follow the pattern and how you implement that is just going to depend on your code and a number of things.

[88:34] This is an example of how each of these requirements has been met from the design pattern. Again, if we go ahead and update, I use my keyboard. I have tab to the tablist. You can see that my focus is on the entire list. I'm going to tab one more time to jump to the selected tab. I'm now in the tablist and I'm using the arrow keys to move forward.

[89:10] This right arrow key, here is left, here is end and here is home. I have it automatically selecting the tab as it arrives. As the focus moves, it's selecting the tab. It's not an extra step for me to move the cursor and then select it. That's how that works.

[89:42] I did not do a demo. I had a timer. Let me show you what that would be before all those changes. Sorry I missed that.

Voiceover: [89:54] Current page visited link action. Visited link drama. Press current page visited link drama. Visited link comedy. Press current page visited link comedy. Visited link Sci-Fi. Press current page visited link Sci-Fi. Visited link fantasy. Press current page visited link fantasy. Voiceover off.

Instructor: [90:23] That just shows you it works. It's OK. We're being told what each of this tab says but they are all being described as just links. We don't really get the context of this being a tablist widget.

[90:38] There's a lot more information that we could be giving the user that would then tell them what they can expect from this thing. First, they know they are just running through a list of links which is really not accurate. It's more than that. After all of our changes, here's what the experience is.

Voiceover: [91:01] Main. You are currently on the main inside of web content. Movie genres tab group. You are currently in a tab group. Action selected tab, 105. Drama tab 205. Press drama selected tab 205.

[91:18] Comedy tab 305. Press comedy selected tab 305. Sci-Fi tab 405. Press Sci-Fi selected tab 405.

[91:29] Fantasy tab 505. Press fantasy selected tab 505. End of movie genres tab group. Fantasy tab panel. You are currently in a tab panel. Voiceover off.

Instructor: [91:44] With those changes we had a ton more context. We were told that when we reached the tablist that we were in a tab group. We were told with each tab is that one selected or not.

[91:58] We do have to take the extra step of selecting the tab when using the screen reader versus when we were using keyboard nav because the screen reader just has the ability to move further with the cursor than keyboard navigation alone.

[92:14] That's why that's a two-step process. It tells you the tab's not selected. You press, it tells you that it's been pressed and then it tells you that it's selected. It continues to tell you it's a tab and how many there are in total. Then when you get to the end, it tells that you that you're at the end.

[92:35] When you go out and move to the next part, it tells you that you're in a tab panel and what tab panel it is. At the very beginning, it told you it read that ARIA label for the tablist saying, "Movie genres," so way more context than just reading through a list of links. It's immensely helpful when you do these things.

[93:01] That's the tablist. I also have exercises here for the toolbar. I'm going to show you real quick the before and after. Please feel free to walk through these exercises and try them out yourself and look at the design pattern for a toolbar.

[93:23] Mostly, what I'm trying to convey here is, what are design patterns? Why are they important? Where can you go find them? What's the before and after? Why are they so crucial? Here's the toolbar. These are the buttons here for each movie.

[93:44] Before we do anything, they're basically just buttons, but they have more context than that that we can give these.

Voiceover: [93:58] Watch Inception button. Edit Inception button. Remove Inception button. You are currently...Watch the Shawshank Redemption button. Edit the Shawshank Redemption button. Remove the Shawshank Redemption button. You are currently on a button. Voiceover off.

Instructor: [94:15] They're just buttons, but I think they can be more. Here's the after.

Voiceover: [94:30] Inception actions toolbar. You are currently on a toolbar. To interact with the items on this toolbar, press control option shift down arrow in Inception actions toolbar three items. Watch Inception button. Edit Inception button. Remove Inception button.

[94:48] You are currently on a button. Inside of a toolbar. To click this button, press control option space. To navigate items on this toolbar, press control option and then arrow, down arrow, left arrow, or right arrow. Out of Inception actions toolbar. You are curren-, [inaudible] Shawshank Redemption actions toolbar. In the Shawshank Redemption actions toolbar three items. Edit...

Instructor: [95:13] Here, I'm just going to cut that one short. You can also hear how it's not just the toolbar, it's the Inception toolbar and the Shawshank Redemption toolbar. We've got all of that extra information that we are giving the user about the toolbar, and it's not just some buttons. That's that one.

[95:34] I got a lot of references here. If you want to go learn more about design patterns, we've got some really good links here to some great design patterns for our common widgets.

[95:46] That brings us to the end of our lesson plan. I appreciate all of you who stuck with me. I guess I just want to it up. Do we have any questions for anybody still here hanging in there?

Audience Member: [96:06] I do have a question. In regards animations and in the design patterns. Let's say I'm on the website, which has min to animation plus the wrong web second and then the content loads, what will be the most accessible way to make sure I can keep the animation, but I gave enough information for a screen reader that there is some cosmetic content ongoing and then the content will actually load afterwards?

Instructor: [96:37] That is a good question. I'm not sure I have experience yet with such a thing. It may be that you need to do something with a live region that reads loading perhaps, or whatever the animation is.

[96:56] Then once that animation is removed and the content has rendered, you would move focus to whatever that first thing you wanted them to hear next would be. That's what my first thought would be for addressing something like that.

Audience Member: [97:14] OK. Like a polite announcement said that the content will be loaded in X seconds.

Instructor: [97:22] Yes, I think so. You might want to also look into that progress bar widget. If you added a role of progress bar, maybe it's something that that would fit in, but if it's not something that you really have...we know where at this percentage loaded, but just a general...

[97:43] It's loading. Then once it's done loading, replace it with something else. It would just read that loading and then move the focus to the next thing on the page.

Audience Member: [97:57] Yes, that's what I did. Yes. Thank you.

Instructor: [98:00] Good question. All right. Anybody else?

Audience Member: [98:11] There were some questions on the chat that we missed out on, but I don't know...

Instructor: [98:16] Thank you for reminding me of the chat.

Audience Member: [98:19] if they're still relevant or not.

Instructor: [98:22] Let's see. Good call out about reach router. That's definitely a good one that's out there that Ryan Florence is probably working on for a little bit. It's got that focus management built in as you route from one page to the next, it will move focus to a specific place.

[98:48] Any reason not choose negative one. Negative one is a way of saying something is not focusable. It needs to be a positive number in order to be focusable. There's really no reason to add numbers higher than zero.

[99:06] Long time ago, we would actually order those to create a tab order. You would actually specify zero or one, two, three, four, five. We don't need to do that anymore. Browsers already know how to logically flow through anything that has the same trap index.

[99:28] If you did use more numbers in that, it could get really clunky or brittle. If suddenly you changed the order of things, you'd have to go update all those tab in next numbers. Really either use negative one to say, "This is not focusable. We do not want to be able to reach this with focus or zero if we do want it to be focusable."

[99:47] All right. Was there anybody else...? OK. Is this now plugged in? Is it? I don't remember what it was called. Yes, it is this. The numbers are low, but I don't find that a lot of people rate plugins, so it's hard to go by the ratings alone. I use it just as a extra tool to help me find suggestions.

[100:28] You just use it as, "Here are some other ideas and here are what the ratios are for those ideas." It doesn't hurt to use that to inform your decision. Level Access is a pretty reputable accessibility company, so I feel like that name provides some clout. 827 users is pretty good.

[100:51] I recommend it, but again, it's just another tool in your toolbox. I think I got everything.

Audience Member: [101:04] I have a question.

Instructor: [101:07] OK.

Audience Member: [101:08] At my company, we're looking to raise awareness about accessibility. We already use some tools knowing that tools don't catch everything, too...

Instructor: [101:20] Totally.

Audience Member: [101:21] like linting. We're thinking of adding some tools and we're doing research now to help raise awareness and catch issues and help raise a level of this. Again, knowing that they don't catch everything, is there any other tools you didn't demo today that you recommend?

Instructor: [101:41] You can use Axcore. We do Axcore. Yes, go there. All right. If you look up Axcore in GitHub, you can actually use that in your automated unit test. DQ Labs, they have a lot of different tools that you can use in a lot of different places, so you could add to your unit test.

[102:20] As those are running, you're checking for accessibility things. That's a little more of an automated way to ding you like, "Oh, something's changed. We just broke something," that maybe you don't have to be manually checking for.

[102:36] There's also a really nice tool that they offer, which is I think enterprise licensed, called the Comply. It has a way of scrapping or spidering, or whatever you want to call it, you can give it a starting URL and it will audit that page automatically so you can schedule this.

[102:59] It will audit the page just like if you went to page and run x, will audit it on its own. It would go through each link on that page to any subsequent pages that you could get to, and it will audit all of those as well.

[103:14] That's another really awesome way to have automation running to tell you if you broke something, without having to be manually checking that stuff.

Audience Member: [103:28] Thank you and thanks for the workshop.

Instructor: [103:30] Yeah, absolutely. This is a good point about Cypress axe. There are a number of different things that are tying in with axe now and making use of that.

[103:46] Another one I'll plug real quickly, Storybook. If you use Storybook to test your UI components and isolation, it also has a little ad on that does accessibility checking.

[104:01] I definitely, definitely do recommend. Use the tools to at least get that 20, 30 percent of things covered, cleared, out of the way so that you can move to the next level that you actually do have to find through manual testing to see what the experience is like.

[104:23] All right. Anybody else? Yes, that one. Thank you, Ryan. If anybody has any questions in the future, you can hit me up on Twitter. My name is...Let's throw this somewhere I can type. I'll just put it right here, @SunshinyDoyle on Twitter and you can send me any questions that come up and I'll be happy to help.

[105:01] Thank you, everybody. Have a great rest of your day.

egghead
egghead

Member comments are a way for members to communicate, interact, and ask questions about a lesson.

The instructor or someone from the community might respond to your question Here are a few basic guidelines to commenting on egghead.io

Be on-Topic

Comments are for discussing a lesson. If you're having a general issue with the website functionality, please contact us at support@egghead.io.

Avoid meta-discussion

  • This was great!
  • This was horrible!
  • I didn't like this because it didn't match my skill level.
  • +1 It will likely be deleted as spam.

Code Problems?

Should be accompanied by code! Codesandbox or Stackblitz provide a way to share code and discuss it in context

Details and Context

Vague question? Vague answer. Any details and context you can provide will lure more interesting answers!

Markdown supported.
Become a member to join the discussionEnroll Today