 So yeah, what's up? I'm Doddle Max of Bob Dodd. And today, I want to talk to you about how we can make sure that, as we build our progressive web apps, that all of our users can access the content in those apps. Now, Paul just showed some really cool examples of how to build amazing components. And as he hit on repeatedly in his talk, we know that performance is not just a nice to have. Performance is kind of a crucial aspect of a good user experience. We know that users will actually abandon an application if it doesn't have the performance that they expect. But it's often the case that when we're designing these components and these applications, we're doing so based on our own experience and our own physical abilities. So we're designing for the range of users who really see and interact with the world as we do. Meaning anyone who falls outside of that range is going to be excluded from our design. So these users aren't abandoning our app. They're actually prevented from using it in the first place. And so as designers and developers, it's important that we not only consider how we interact with the world, but we really think about the full range of human abilities. And this becomes especially important when we're talking about mobile. Because as we use our devices in different contexts and in different environments, we may, too, experience situational or temporary impairment. So to give you an example, I'm sure many of you have had the experience of trying to use your phone or some electronic device outdoors when it's really sunny. And you need, like, you can't really read the screen, so you're kind of like doing this thing, right? You need some additional contrast on the screen so you can actually read it. So if we have a design that also factors in the needs of low-vision users, folks who also benefit from increased contrast in their reading experience, then what we end up with is just sort of a more robust application. It works well for those users. It works well for us as we take our mobile devices out in the sun. In other words, accessibility just equals good UX. I'm getting the crazy slider, too. There we go. Accessibility is just good UX, right? So this is what I want to talk about today. How do we make sure that all of our users can access the content in our apps? I'm going to do this by splitting this talk into three parts. So the first part is looking at really the diversity of users that are out there and touching on the accessibility topics that affect them. Then I want to look at two big areas that developers often miss, which are particularly focused on focus and semantics. But I want to start just by understanding who our users are and the kinds of business technology that they use. Now, I'm going to focus on users with permanent disabilities. But again, I want to reiterate that issues of accessibility really do affect all of us, ensuring that users with disabilities can access the content in our applications. It's just going to make a better experience for everyone. But having said that, let me get some numbers out there, because I think these are pretty fascinating. So according to the World Health Organization, about 15% of the world's population lives with some form of disability. So to put that another way, we're talking about around 1 billion people worldwide. And we can roughly split these into about four different categories of impairment. Those affecting visual senses, those affecting motor and dexterity, auditory senses, and cognitive senses. And I want to cover each of these individually, starting with visual senses. So users with visual impairment, you can kind of split them into two groups. Those folks who might be completely blind and have no vision, which are those folks who might have limited or low vision. Someone who is completely blind might use a screen reader. This is TalkBack on Android to interact with their device. They may also use a Braille reading device to access their desktop and have it sort of translate the content for them in that environment. So that's users with no vision. Users with low vision, they may also use a screen reader, or no, go back, there we go. They may also use a screen reader, or they may choose to use screen magnification. They might use built-in zoom that's at the operating system level, as you're seeing here. They might use browser zoom, just command plus to zoom in the page. They may also use something like high contrast mode. So here you're seeing that the background and the foreground colors have been swapped to increase legibility. So that was vision. For motor impairment, these users really span the gamut of folks who maybe would prefer not to use a mouse, because they have something like repetitive stress injury, something like carpal tunnel syndrome, or maybe even just a broken arm or sprained wrist, all the way to someone who might be physically paralyzed and have a limited range of motion. So for these users, they may be using head or eye tracking devices. This is an example of a program called Dasher, which uses a webcam to track the user's head and eyes and help them type. They may also be using a keyboard or a switch device, as you're seeing here, to actually drive their computer. They may also use voice control. So there's a lot of different mechanisms that they can use. For auditory impairment, these users range from those who are profoundly deaf to someone who is hard of hearing. So I'm actually in the hard of hearing camp. I've got about 90% hearing loss on my left-hand side. So for these users, you want to make sure that you're not relying solely on sound to convey information in your app. So making sure that if you have a video, right, you've got captions, that you've got transcripts, that you're providing some kind of alternative if sound is part of your interface. And finally, for cognitive impairment, this is really a broad area that can be difficult to quantify. But it spans conditions like ADHD, dyslexia, autism, just to name a few. And while the accommodations for these groups are obviously extremely diverse, we definitely find some overlap with things like zooming to make it easier to read and easier to concentrate on the page. So this is a Chrome extension for someone with dyslexia. It applies color gradients to the text to aid in their reading order and help them read in kind of a more linear fashion. So broadly speaking, these are the four categories that we need to think about when we're working on accessibility in our app. Now, because accessibility is so broad and the usership is so diverse, it can be helpful to have a guide to make sure that we are covering each of these groups. And we can find that in the form of the web content accessibility guidelines 2.0 or WCAG. WCAG is basically a set of best practices which have been put together by accessibility experts to really try and explain what it means for something to be accessible. And WCAG is extremely comprehensive, but it can also be overwhelming. I know some folks look at that and they're like, that is not a thing I want to read right now, right? So to help mitigate this, the WebM group has actually taken WCAG and distilled it down to a very easy to follow checklist, which is targeted specifically for web content. So if you were watching those videos earlier and you were wondering, wow, how am I going to possibly cater to all of these different users and all these different assistive technologies? I think the short answer is to nail that checklist, okay? Figure out what the primary user journeys are in your application. If creating a new account is an extremely important process that you want all users to complete, then take that user journey and for every step along the way, make sure you can check off those relevant checklist items. And do this for every phase of your process, right? So get your product managers bought into it, get your designers bought into it and make sure you're having accessibility audits in your design review, get your developers bought into it, get your QA team bought into it and checking these things to ensure that the burden does not rely on one person. So with these checklists in hand, we're actually ready to start exploring some of the fundamentals which we'll need to actually complete those checklist items. And I want to start by looking at focus and really like, what is focus? Like what does it mean for something to be focused in the browser? If we really try and get down to first principles. So in a nutshell, focus determines where keyboard events go in the page. To give you an example, if I go and I click on this text field, that act of clicking on it actually focuses it and from then on as I'm typing on my keyboard, all key events are directed to that element, which in this case knows to display the characters as I've typed them. Now some users drive their computer entirely with a keyboard or some other type of discrete input device. So for these users, focus is absolutely critical because it's their primary means of reaching everything on the page. It's also really important for our screen reader users because if we're building something like a single page web app and we're adding new content to the page, right, we're fading in a new page or something like that, then we need to direct focus to that page so the user knows that it's loaded. They know it's available and their screen reader can announce it and we'll talk about that a little bit later on. Now, a lot of the controls that you're familiar with working with, things like button, input, select, all these elements are implicitly focusable. What that means is they are naturally inserted into the tab order so user can reach them hitting the tab or shift tab keys on their keyboard and they have built in keyboard behavior support. So if you take a select element and you hit the up and down arrow keys, right, you can select something. If you hit space or inner, it'll select something, right? So they have a lot of goodies built into them already but not all elements are focusable. So for instance, this header here, this paragraph of text, this image of a cat, these are not focusable because there's generally no need to focus something if a user can't interact with it or provide it some sort of input. Now, if you're worried that someone with a visual impairment might miss some of this important content, don't be. That's why we have tools like screen readers. It's a screen reader sole job is to read headings and read text and read the content of an image using alt tags. So don't make something focusable if the user can't interact with it. That might seem like you're helping out but it's actually detrimental to the user experience. And this brings up an extremely interesting and important point, which is that if you build your interactive controls out of these sort of non-focusable elements, a div for instance, then your users may not actually be able to interact with it at all. So I'll give you an example using Paul's side nav. This is actually not Paul's exact side nav. I've modified it a little bit. But you can see here that I've got my little hamburger menu up there in the top left. And obviously I want to tab over and click that to open my menu. And right now my focus is on that little start anchor up there in the header. So as I'm tabbing around or hitting shift tab in this case, you'll see that my focus never lands on the hamburger menu because it's a div and a div is not focusable. So if I am a keyboard or switch device user, I may potentially never be able to click on that menu ever. So how do we fix this? This is obviously a bad user experience. Well the straightforward thing to do is instead of using a div, we can just use a button element, right? So now when the user goes to tab over to it because button is easily styled, we can make it look like a hamburger menu. Now they're inside of our drawer, things are all good. A side benefit of using a button element in this case is that the browser actually has built-in magic that you get for using certain tags like button. So a button element, if you give it an on click handler and someone lands on it, they focus it and they hit enter or space bar. Even though they didn't click with their mouse technically, the browser will just say, enter your space bar, yeah, I'm gonna run your on click handler for you. If however, you have a div and you make it focusable and I'll talk about how to do that later and you have an on click handler on that and someone hits enter or space bar, nothing happens. You actually have to add an additional key down handler and then you have to check which key was clicked inside of the key down handler. So there's really no benefit to using these kind of like less or non semantic elements to do this kind of work. In other words, don't fight the platform here. So the browser has a lot of built-in stuff. It's trying to save you from having to write extra code. But I realize, you know, there's not always a native element that has the behavior that you need or as is often the case, there might be a native element but it might be really hard to style. Things like, you know, checkboxes and radio buttons, input file, that thing's impossible. So if you are gonna go and build a custom control, it's important to remember that you just have to add that keyboard support back in. And you can do that using the tabindex attribute. So tabindex lets you kind of configure the focus behavior for an element. And it can be applied to pretty much, I guess, many or most HTML elements. A tabindex value of zero is gonna just insert that element into the natural tab order, meaning someone can hit the tab key on their keyboard and they'll easily reach it. It also means that we can call its focus method to programmatically focus it. So here I've got this very fancy button that I've created. Right now if I press tab, focus is just gonna move right past it. So I give it tabindex zero. Now when I press tab, focus lands on it and we're all good. Tabindex negative one means that the element will not be in the tab order. But this can be really useful if you still need to programmatically focus something using JavaScript or if you want to like temporarily disable a control. So what I've got here is kind of a list control and I might have like a hundred items in this list. So I wouldn't want all of those to be keyboard focusable because a user's gonna hit tab over and over and over and over and over again to get through them. I'd like the entire list to be a single tab stop so user can just like move into it and move out if they need to. But when they're inside of it, maybe if they hit the up and down arrow keys or something similar, maybe then I can change which item is currently selected. So to do this I'll use a technique called roving tabindex or roving focus. And you can see here in my markup, my currently selected item has a tabindex of zero. And so what I'm gonna do is listen for the user hitting the up and down arrow key. When they hit down, I'll just move the tabindex zero to the next element. I'll call focus on it. That directs all of our attention to it. But if the user wants to, they can still tab out of this control. But when they tab back in, right? The last thing they interacted with is focused for them. This is an extremely useful technique if you're building sort of complex controls and other elements. It has obviously great browser support because we had tabindex for quite a while. So definitely commit this one to memory if you're building anything advanced or super fun like that. Now you can also have a tabindex value of greater than zero. You can have a tabindex of like five, which just means it's gonna jump that element ahead of everything else in the tab order. And this is basically considered an anti-pattern, but I wanted to include it for completeness sake so that you know that it is the thing that you could do. The reason why this is an anti-pattern is you can end up creating a super confusing tab order if you do this. And you're mixing matching components, maybe by different authors and they're using tabindex greater than zero. Things could get wild pretty quickly. So in general you wanna avoid tabindex greater than zero if you can help it. Now I wanna revisit the side nav that Paul showed earlier because it presents an interesting couple of use cases for tabindex. If we think about a side nav, when we open it, we want the user to be over there, right in the drawer. Either clicking a menu item or dismissing it. We definitely don't want them over there behind the overlay, maybe interacting with the page when they shouldn't be. But if someone is using a keyboard or a mobile screen reader to open our drawer, there's really nothing that automatically moves them into that side nav drawer. And I'll show you an example of what I mean by this. So this is mobile Safari running voiceover. This is hands down the most popular mobile screen reader setup out there. About 70% of the people surveyed who use mobile screen readers use mobile Safari and voiceover. And you can see this little black rectangle up there on the reload button. So that is where my screen reader is currently doing its thing. And I want you to watch what happens here. So I'm gonna start swiping to move the screen reader. I'll land on the hamburger menu. I'll double tap to select it. It looks like I'm inside the hamburger menu, but I'm actually, or sorry, it looks like I'm inside the drawer, but I'm actually still just in the header. I was still sitting on the hamburger menu. Now I'm just moving through the header when I probably shouldn't be. I might be interacting with the page when the author isn't expecting it. So my user's context hasn't been updated. They're not even sure if the menu is open yet. And if you have a site that has one of these kinds of menus and you have not done any work to direct the user's focus into your drawer, this is probably how a blind user or a screen reader user is gonna interact with your app. So how do we fix this? This is obviously not a good situation to be in. Well, one approach is to find a suitable heading inside of that drawer. I've got this one right here that says menu, and that seems like a good one. And I'll give it a tab index of negative one. So remember, when I give something a tab index of negative one, it's not in the tab order. The user can't reach it hitting their keyboard, but I can programmatically focus it using JavaScript. So now when the drawer opens, I can call its focus method, and now the user's gonna be directed inside of here, and they can start acting on the drawer very easily. So I'll show you an example of that. So same experience, we double-tap the drawer, and we just move right to the menu, and the user can keep moving with their screen reader. They know exactly where they are, and they have that nice sort of continuity to their experience. So this is a technique called managing focus, and it can be extremely, extremely valuable for your user experience. It's useful for situations like this. It's useful if you're building a single-page web app and you're fading in a new page. So super good technique to have in your back pocket. Now let me show you another issue that I found, specifically relating to tab index and this side nav. So this is more of a kind of a desktop, say, version of the site, and I want you to pay attention to what happens to my keyboard focus as I tab around the screen. So I'm gonna focus those two things, and then it kind of disappears, and then it focuses that anchor. So watch that again. We're kind of moving around in the header, and then we just disappear for a little while, and then we focus that anchor in the page. Now I'm actually hitting tab the whole time we can't see our focus ring anymore. And what's happening is because we have that drawer off-screen and because inside of that drawer we have anchors and things like that, focus is just moving off-screen. It seems like it disappeared, but it's actually just over there somewhere where the user can't see it. Now we probably don't want someone to be able to interact with off-screen content, especially if we're kind of trying to hide it on purpose. Again, this would cause sort of an error state in our application possibly, and it can be very confusing for the user. So how do we fix this? By the way, I see this all the time. You should go to some big websites and start tabbing around. This will totally happen to you. Okay, so how do we fix this? Because it's a super weird situation to be in. Well, the first idea is like, well, the thing's off-screen, right? So let's set it to visibility hidden, you know? It's off-screen. That makes sense. It is hidden, anyway. And this would totally work. But if you recall in Paul's talk, he talked about primed elements, and he talked about flip, and he talked about this idea of having your elements already kind of like in the DOM, already like ready to go. And if we set them to visibility hidden, then we're gonna destroy the compositor layer, right? We're gonna have to do all that work all over again every time the user presses a button. So that seems like maybe that's not the best solution. And to me, this is really frustrating, because I feel like developers and users should not have to choose between 60 frames per second animations and good accessibility. So I tried to come up with two solutions to this problem. The first is to ignore Paul and say, I win and I get what I want and set it to visibility hidden, anyway. And the reason why this is potentially workable is because, as Paul mentioned in his talk, you do have about 100 milliseconds from the time a user clicks on something until the time you need to start animating. So if our drawer is simple enough, then maybe we could get away with actually setting it to visibility hidden and recreating that layer. So the way we do this is we listen for the transition end event for when that drawer is off-screen, right? I checked to see, hey, does it have the side nav visible class, which was how I know that it was either on-screen or off-screen. If it doesn't, I'm just gonna set it to visibility hidden and do you sort of like vice versa for when we animate it on-screen. So what does this look like in the timeline? Here's Paul's original version. And the time that I am interested in is this little block right here. So that's the time. The yellow bit there is the click. The end of that blue rectangle is sort of when we ship the next frame. So right now it's about eight milliseconds in Paul's current version, well within that 100 milliseconds range, right? And if you look down here, you can see the amount of painting that we're doing. So I've got these two little chunks of painting that are happening, because this thing's already in the, but now we don't have to paint it much. So here's the version where I set visibility to hidden. You can see that there's definitely more paint work going on. But if we look at our time range here, it's about 10.4 milliseconds. So we added a little bit of time, but not too much. And a lot of that time was actually idle time. So in terms of how this frame stacks up with Paul's version, they're pretty similar. And again, it's because we can get away with this because the drawer is super simple, right? It's a very simple element. If you had a bunch of images, a bunch of icons inside of there, and that paint may be more expensive. So this leads me to option two, which I am calling the Detabinator. Unfortunately, there's really no easy way to remove all focusable children of an element from the tab order. You have to go to every single child and set it to tab index negative one. You can't just set it at the parent and have it cascade down, which is a bummer. So that is basically what this library does for me. I created Detabinator, and I give it the side nav element. And when I set it to inert, I set all the children to tab index negative one. I set it to inert false. I restore all of their tab indexes. The way that I do this is really gross, but I wanted to show it. So I have this query selector all, right? And I have this lovely query selector string inside of there to select everything that could possibly be focusable inside of an element. And this is not entirely bulletproof. There's weird quirks here. If you have links inside of SVGs or stuff like that, it may not be bulletproof. It may not be perfect, but it does probably, for general use cases, do the right thing. Then for each of those children, I'm going to loop through them. If they already have an explicit tab index, I'm going to save that. Remember when we set that menu to tab index negative one, because we wanted to manage focus, so I'm going to hold on to that so I don't lose that information. And then I'll set everything to tab index negative one regardless. And when we're going to open the drawer, I just restore all those values, okay? So here's the Detabinator version in the timeline. You can see our little block of time right here is back to about eight milliseconds, 8.4 milliseconds. So we're pretty similar to where we were with Paul's original version. And if we look at our paint time, we're back down to sort of like two little blocks of painting. So hopefully we're in sort of the same ballpark. Now again, there's sort of trade-offs to each of these. The visibility one, you have to do a little bit more work there in terms of painting. With Detabinator, you would also have to add things like are you hidden to prevent a screen reader from going in there, so there's additional work that would be required in that case. But again, what I'd say is, maybe if you're running into this problem, try one solution or the other, measure it, see which one works better for you and which one your team prefers. Okay, we talked a lot about focus. I'm gonna switch gears now and talk about semantics. So this is the other half of ensuring we have a good user experience. Semantics is really crucial for making sure that our screen reader users can understand the content of our page. And the first question that comes to mind when I think about semantics is like, well, what does good semantics mean? Like again, let's get to first principles. What the heck does it mean if something is semantically rich or right or whatever, right? And how does it actually benefit someone? And I answered this question and it helps us think about this idea of affordances. So an affordance offers or affords a person an opportunity to perform an action. And a teapot is a really great example. So a teapot just based on its physical design has affordances, it has a handle. And because I've seen other things in the world that have handles, I know that I can walk up to a teapot and pick it up by that handle and interact with it. No one has to explain to me how a teapot works. Now, when it comes to graphical user interfaces, affordances still represent the actions that we take, but now they're kind of more metaphorical. So a button is a good example, right? Someone can't like go, you know, touch the screen and feel the button. So we try to make it look like a three dimensional button that you might actually interact with in the real world. But the obvious problem with this is that if someone can't see the screen, then they're gonna miss out on those visual affordances. So we need to make sure that the information in our application is expressed in a way which is flexible enough to be accessed programmatically by assistive technology, which can then create an alternative interface for those users. So I'll give you an example of what I mean by that. Here I've got some semantically rich markup. So I'm using a select element to create a list. And this is gonna generate a visual UI, right? But because I've used good semantic elements, it's also gonna produce this alternative UI. It's gonna produce a spoken UI for a screen reader user. Now, roughly speaking, for just about any element, you can expect some subset of the following semantic information to be expressed for it. The element will probably have a roll. So the select element, in this case, its roll is pop-up button. It will have a name. And I don't mean like a name, like the HTML name attribute, but you can think of the name kind of like its label or the sort of the computed text value of that thing. The element may also have a state. It's optional. Some elements have states, some don't. And it may also have a value. Again, that's optional. But in this case, we have a value of no preference here. So what's happening is when we write HTML, the browser does two things. It generates a graphical user interface and it generates a separate accessibility tree, which is just a collection of all that semantic information that I was just going through. This tree then gets handed to assistive technology, like a screen reader, and then that produces a spoken UI for our user. So this is actually why semantics really matter. Even though Nav and Div look the same, right? Because they don't look like anything. They just look like a container. Semantically, it produces something very different in the accessibility tree. So as I mentioned, just like with focus, native elements, many of them have implicit semantics. So for example, a voiceover on Mac when I focus an input element with type equals password, it's going to announce secure edit text to the user. And just like we saw with focus, when we try to bolt functionality onto non-semantic elements like a div, then we end up missing out on all these goodies that the browser is trying to give us for free. So here's another div button, another very fancy button, and it's got tab index zero, so it's focusable for sure. But when a user lands on it with a screen reader, the screen reader will say group, because it is just a grouping thing. It's a container, right? But that definitely does not say to me that I should click on it. So again, don't fight the platform here. Whenever possible, use native elements because you're gonna get good, rich semantics for free. And just as an aside, like I hope at this point, no one is considering writing a div button ever again. If anyone leaves here and writes a div button, I have failed all of you. But there are times when you're gonna need to build something that just doesn't have a native element equivalent, or you need to just go off-road and do your own thing. And in those situations, you can use the web accessibility initiatives, accessible, rich internet application spec, or ARIA. So ARIA allows you to specify attributes on an element and then basically modify that element semantics. You can think of it like doing surgery on the accessibility tree. However, semantics is the only thing that ARIA changes. ARIA does not change behavior. So I used to think if I put like a roll equals button on something that it magically became focusable and worked awesome with a keyboard. It's not the case. All it does is change the semantics to get expressed to assistive technology. So let me give you an example of using ARIA in practice. So here I'm gonna build a custom control. I'm gonna build a checkbox, a custom element checkbox. And in this box down here on the bottom right, I'll show the output from my screen reader, just the textual output, right? And the first question when I look at this checkbox is, hmm, okay, I'm building a checkbox. I want it to be accessible. What do I need to add to this? What sort of ARIA do I need to add? Now there's two approaches here. The first, you can go look at the ARIA spec, which comes with this very helpful diagram. Or you could go check out this document called the ARIA Authoring Practices Guide. And this document is a bit of a hidden gem. It is pretty freaking cool. So over on the left-hand side there, you see all the UI patterns that you could probably imagine. There's a ton of them in this document, right? Grid, dialogue, tree, whatever you're trying to build. Checkbox, for instance, is included in there. So you click on the UI pattern, and I'll take you to a little section, and it's just gonna walk you through all of the support that you need to add to that element. In particular, there's a whole section down here dedicated to the ARIA that I need to add to a custom checkbox. So it says it needs to have a roll of checkbox, it needs to have an accessible label, which we'll talk about, it needs to have a state of ARIA checked if either true or false. Okay, cool, so let's add this to our checkbox. I'm gonna give it a roll of checkbox, and you can see now my screen reader is announcing unchecked checkbox. Nice. Now in the world of ARIA, roll is the absolute most important attribute. Everything falls out of the roll, okay? There's a lot of ARIA attributes which don't even work if they are not paired with the proper roll. So, and you can also see that now my state is just defaulting to unchecked because of the roll, right? So it's like trying to start doing stuff for me, it's like coming alive, which is cool. But you see that my checkbox actually is checked, so I need to change that state. So I'm gonna add ARIA checked, and I'm gonna set it to true. And ARIA is sort of unique in that you always need to pass it like a literal string value of true or false. Most HTML attributes do not work this way, but this is the case with ARIA, it's kind of a weird quirk. Now the design pattern doc also mentioned I need labels for this thing. And there are a couple options for how I can label an element. The first is ARIA label, which is really just a label that you can apply directly to an element. A good use case for using ARIA label is something like a hamburger button where I probably wouldn't have any other text on screen to explain this thing, but I need to explain it for assistive technology. So what I can do is take that button and add an ARIA label of main menu. And now it'll announce main menu button. Okay, that's good. That's one option. The other option is ARIA labeled by. So ARIA labeled by lets you specify another element to act as your label. It's sort of similar to using the label element like it might do with a native input, but that element really only supports a few kinds of children, whereas ARIA labeled by can be applied to just about anybody. And the cool thing about ARIA labeled by is that it can be composed. So I can take other elements and combine them together for a bigger label. In this case, I got this button that says shop now and if you look at our text up there, the screen reader is just gonna announce shop now button. I don't know what I'm shopping now for. I'd like to combine it with that header. So using ARIA labeled by, I can take both the header and the ID of the button itself and compose them together to create the label men's outerwear shop now button. Nice. So this is what I wanna do in my checkbox. So I have this little span here. I'll give it an ID of sign, drop it into my labeled by, and now the screen reader is gonna announce that I have sign up, checked checkbox. There we go. Nice. Now if you are building controls and you want to verify your work is correct, I highly recommend you check out the Accessibility DevTools extension created by my teammate, Alice Boxhol. This thing is awesome. It lets you inspect your element's accessibility properties the same way that you inspect CSS and other things like that. So here's our sign up button. I'm gonna open it up, go to my elements panel, find this element, and then I can go check out its accessibility properties and see now its role and its values and its name and all these other cool things. So I don't have to go around with a screen reader and manually test every single element. So this is super handy to have. You can find it at bit.ly slash a11y-devtools. Another cool example in the Progressive Web App space is this app created by the Polymer team called Shop. I really love this app because I think it shows off that you can build these bleeding edge beautiful experiences using web components, all the Progressive Web App tech that we're talking about, but still have it be really accessible too. So you can see the text down here. This is the output from my screen reader and as I'm navigating around, it's giving me lots of really useful actionable feedback. It's telling me the proper thing that I'm interacting with. So definitely go check out Shop. You can find this at github.com slash Polymer Shop. If you find any accessibility issues, please file them. We want this to be like a show piece of web components and a good accessibility. All right, we covered a lot. Let's wrap it up really quick. Three big things that I want you to take away. When you're planning your applications, make sure that you're really nailing that web-aim checklist. Familiarize yourself with WCAG and ensure that you can go through those user journeys and for every major primary use case, you can check off the relevant checklist items. If you're building controls, you want to ensure that they have good keyboard support and that everything is focusable. Use native elements whenever you can because it's just going to save you a bunch of work. If you need to create your own elements, use something like Tab and X to make sure that the user can interact with them. Also, make sure that you're offering the right affordances in your app. So again, use native elements because they have rich semantics for free. But if you need to go off-road, you can use something like ARIA and that ARIA design pattern stock. Seriously, that thing's a lifesaver. So definitely check it out. Now, if you're interested in learning more about accessibility, myself and Alice Boxall, we have put together this entire Udacity course. It's launching today, I think, actually. So if you all go sign up, it'll be some of the first people. So it's bit.ly-slash-web-a11y. This is a multi-week course. It goes super in-depth on all of these topics. So definitely please go check this out. Finally, the main takeaway that I'd like for you all to leave here with is this idea that accessibility is just fundamentally good UX. Ensuring as many users as possible can access our content should be our primary goal at all times.