Get started developing with accessibility in mind in this Angular workshop. Join us as we take a basic application and look at eight ways to enhance the usability to ensure we are developing for all users.
Resources: Codelab → https://goo.gle/3EmVZxk Code → https://goo.gle/3jJGwPU Angular DevTools → https://goo.gle/3mlIgjX
Speaker: Emma Twersky
Watch more: Watch all Chrome Developer Summit videos → https://goo.gle/cds21-allsessions
Subscribe to Google Chrome Developers → https://goo.gle/ChromeDevs
Hi everyone. My name is Emma Torsky, and I'm a developer relations engineer at Google on the Angular team. And I'm Super excited to be here today talking about how to build build more accessible Angular applications. So we're going to spend the next hour and a half ish talking all about accessibility and Angular and web accessibility. And I'm happy to answer any of your questions along the way. But to get started, I know there were some links sent out ahead of the time, but you can find everything that we're going to be talking about on Codelabs developer Google.com Angularaley. And I'll throw that in the chat as well. And also that a few more times as I see people coming in. So that's where we're going to have to get started. And so let's talk a little bit about this topic first before we dig into some code. And I really want to spend the most time looking at actual code, asking questions about some common pitfalls and stuff like that. But just to back up before all of that, let's talk about why we should care about accessibility. Right? So accessibility is super important for all web developers to know about. It really touches every point of the development lifecycle, from design to development to testing. Everyone needs to sort of have an accessibility hat on as developers and anywhere in that. And in fact, one in four US adults have been found to have some sort of disability that impacts major parts of their life. So you can think about that as obviously there are some of the things we initially think about when we think about accessibility. So things like blindness or low vision, deafness, hearing impairments, motor restrictions, things like that. But it can also be things that are temporary. So things like maybe I broke my arm a few years ago and I couldn't type with one hand, and it made it much harder to navigate my job. How do I code with only one hand, especially if it's my left hand? I can't do anything with my left hand. So I think it's really important to think about the fact that accessibility is really important for a certain part of the population, but it applies to everyone and we can all benefit from it. A great example of that is if you think about closed captioning, right? I have closed captioning on in this Google meet. And if that's something you're interested in, I would highly recommend going to the settings tab at the bottom and turning those on, because sometimes it's hard to understand certain words that people are saying. Or I watch Netflix a lot, and I always turn on my closed captions because sometimes I have the volume low so that I can be doing other things where I'm vacuuming while trying to watch TV. Right. And so while I was not the intended audience of that accessibility feature, I benefit from it. And if you think about that more broadly, adding accessibility to your web applications that you're building, especially in Angular, just broadens the impact that that website can have and the usability in general. So important from a web standard perspective, but also important just because it makes things more usable. So to dig in today we are going to be building an application. I have all of the source code for you to get started. I thought it'd be fun and cheeky to do a dumpling shop. I love a good dumpling. Maybe throw in the chat what your favorite form of dumpling is? I am really into gyoza right now. There's really good cheap dumpling shop down the street from my apartment. But we will be taking an application that I intentionally built without really thinking about accessibility in mind. And we will be addressing eight different pitfalls of things that I think everyone can go back to applications you're building in your daily life and add some accessibility in there. I'm also happy to answer any other questions about Angular. I work on the Angular team and I'm Super excited about our focus on accessibility right now. So we are going to navigate to the next tab here. And can everyone see my screen? Is this large enough for you all? Feel free to throw in the chat any questions you have, or if you need me to go back to a line of code or anything like that, I'm happy to do that. So to get set up again, this link was sent out to everybody, but I just want to make sure you're going to go to the GitHub Codelabs repository here on GitHub. You're going to clone my repository. I already have a fork of it. I see some other people have done that. Maybe you've started Oops, I'm not locked in in this browser. You cannot see that I in fact have started my own repository, but we're going to be working from this. So make sure to fork fetch my branches and we're going to be starting on the get started branch. So in your local set up, I am assuming you already have Angular NTM installed. You have everything up and running, but if you are struggling to do anything there, please make sure you can go to angular. Ilstart and that will get started. So if you're having any dependency issues with like TypeScript or getting the Angular CLI up and running or anything like that, this is going to be the tab to go to and maybe just for the rest of the code up you'll just follow along and look at my code. But that said, we have our GitHub repository, we've taken our code, we've cloned it locally. And so I have my local version here. Again, just this Angular accessibility repository in my local and you're going to want to make sure you have NPM installed. I've already done this, so hopefully it's all cashed and then I'm going to have ng served. So here we're just going to run Ng serve again. I already had it once, but I'll do it again for you. And we're going to use the CLI to make sure that we can build our code. Look at some lobsters in the background. I highly recommend having a cool computer background to look at while you're building. And the super exciting thing about this is compiled successfully. The super exciting thing about all this is I'm doing this all in Angular version 13. So if you've been following Angular closely, version 13 has only been out for like a week, so maybe this is the first time you're touching version 13 code. Kind of exciting, kind of cool. I think everyone should give a little Pat on your backs for that. We love an updated code repository, and this is what we built right? So if we go to our localhost, this is our repository and we are currently on again. If I just check out my get branch to go back to my terminal, I can see that if I do get branch, I am on the get started branch, so make sure to fetch both branches. There should be two get started is where we're starting in our starting place and the main is where we're headed. So if you at any point get lost along the way, you can always go to Maine and all the code will be there that we're adding. And the other way to do that just to give you that ahead of time, is that if we go to main, we can see in our commits on GitHub that each one of the steps were about to do are all an individual commit. So if any one of these changes somehow gets ahead of you, you can also just check out on a certain commit on GitHub. So let's go back to the code lab. We have our code, we've checked it all out. We feel good about it. Let's talk about this application. Besides being a dumpling application, I just want to take a look at what's there. So my photos are in dark mode. I'm going to do that so that my face is less pink for the light. But we have our shop, which is our main page. Also, if you click the home and it has a bunch of dumplings so I can see what I'm buying in my make believe land. The idea here is that I get to pick. I can order up to twelve or 13 dumplings. So this is like a custom dumpling website. I know a lot of holidays are coming up. Maybe you want to order like some really fancy special dumplings for a loved one. So we get to pick what feelings we want in it. We get to pick how many we want. And then the super cool feature of my dumpling website, I've decided is that you can also die your dumplings to a series of rainbow colors. So for example, let's get some like sky blue chicken and box way dumplings and you can click Purchase. Obviously, that has not built out, but in our console, we are logging that. In theory, we are purchasing these dumplings. We could send you to Shopify or something. Right? If you want to know more about this make believe dumpling company, I have an about page, and then you can also find us again. It's a development mode, so you can't actually find us. We're located somewhere in San Francisco. I am also located somewhere in San Francisco. So I thought that was fitting. And we have generally good hours. It is actually after hours for us today locally. But that's okay. We're going to continue with our dumpling purchases. So Besides that, if we look through more of what's going on, let's look at the accessibility of this website. Right. So like, great. I built like a cool, fun application. I think it looks kind of cute, but we recognize it's not accessible right out of the box. There are some things that I feel like I could have done better to build this in a more accessible way. And this is what I really want to focus on today. So to start out by recognizing what we want to fix, there are two types of accessibility testing that I want to talk about today. There's manual testing, which is going to be where the bulk of your accessibility testing happens, right. So this is where I as a user, I'm going to say, like my designer told me that I need to be able to go to my website, select any type of dumpling I want, click Purchase, and know that I purchased those dumplings. And that is a user flow. And I want to make sure that an accessible user, using something like a screen reader could successfully do that. So if I was a developer, I would turn on voiceover, I would navigate, try and do that workflow and make sure that it still works. The other type of accessibility testing is going to be automated testing. So this is where we use other tooling. For example, today we're going to be using the Lighthouse tool and Chrome developer tools to run an automated check for other things. Now, the thing about this is we can't automate all accessibility testing, at least right now, right? Something that's really important in accessibility is that when you are read the choices on a slider that you understand what those means. So there's a cognitive aspect of that. And like, computers are smart, machine learning is getting there. But we can't automate knowing that a user will understand what's being read to them. We can say a user is being read a sentence and that can be automated. But does that sentence make sense? Is where the manual part comes in, if that makes sense. So to run our automated test, we're going to go into our application again, we're going to go into if you hit command option. J, we're opening the Chrome developer tools again. I'm working in Chrome. It's going to be a little bit different if you are using a different browser and I'm going to go to the Lighthouse tab. If it doesn't show up there, then it might be just under these dropdowns and it's going to be one of these. You can see also have the Angular dub tools. My favorite ism is Clear and we're going to pick which ones we want. So for today, just for the sake of time, I've already run these reports, but we're going to pick Accessibility and then click Generate report. It looks like I'm going to have to do it again anyways. Cool. And it's going to run my report again. I just clicked I only selected desktop. You can also do this for mobile. So we're just talking about the desktop or web accessibility for the sake of time. But there's some other cool stuff in Chrome if you want to do it anyways. So we got a report, we got 87. So that's not bad, right? That's 87 points out of 100, right? 100 would be here. So we're doing pretty good. But we can do better. I want to hit 100. I'm a perfectionist. And also I want to make sure this works for everyone. And if there are things I can fix, I'm going to do it. And we see that we have some things highlighted here and we're going to add them to our TD list. Then the third type of check that we're going to run is Linting. And so this is where in Angular I'm using es. Lint. And I'm specifically looking at the Angular es. Lint rules to make sure that I can lit my code. So this is before it even compiles. Like, are there things wrong with my code that I could have fixed? And so I have let's see, one, two, three. I have ten different checks here in my ESLint rules. So if I go to the eslintrc. Json file, I can see those and I accept them all to two, which means an error. Which means if I have Lint checks on and I run Linting, it's going to run an error. These are the ten things that Lint can do. And this is even more than like the usability of what's on the screen. So things like color and stuff like that. This is like, hey, this slider should have a role or something like that, right? So to do this, we're going to open our code. So here back in my terminal, I'm just going to run code and open this and I have it right here and my code opens and I can go to again that Linting file and I can look at my lit rules and I can see that I have again, ten rules here set to those things for my ESLint rules. So if you're using Es Lint, and these are also available in other lending. It's going to be the same rules, just a slightly different declaration. For your Angular applications, I highly recommend that you add accessibility check rules. So I have them here. And that means again when I go back to my terminal and I do Ng Lint, I can see my Linter is going to run. It's going to say, hey, I'm checking your code for all these things. There's an error. Right. And so the two here is saying I want to make these errors. I believe that they should be strict. Right. My recommendation is obviously if you're using a large repository, maybe introduce them as a one. And that's going to throw a warning. Two is going to be an error. And depending on your CI CD pipeline, it's going to stop you from building. Right. But we want that, right? We want to write the best code we can. This is going to push us to do that. And so this link is finding what's, finding it's, finding that any click must be accompanied by a key up, key down, or key press. Right. So I have something in my shop component that I'm saying you can press or click and I'm not actually giving any sort of instructions to it. And so we're going to fix that. So if I go back to my code line, those are the different ways we're going to test. So again, I've collected all of the errors here and I've collected my Linting errors here. And so let's now go through each one and talk about the code, which is probably what you're here for. We're going to start with maybe the largest issues and work down in Granularity and see how much time we have. And I'm happy to answer questions along the way or at the end as we do this, we can also talk about coding best practices as we do this. So to start with what I think every Angular developer, if you're walking away from this, if you do nothing else, if you turn off the video right after you're doing this, I want to make sure that you are defining unique page titles. So single page applications, which Angular is, are super powerful. Right. Because the whole idea is like I have one page, I have all these things. But at the end of the day, this is all one page and I'm changing out components with a navigation. But really this is one page and that's super powerful for development. Most modern frameworks use this sort of architecture. There's a lot of really great performance benefits. It really is the modern web. Right. This whole idea of like a single page application. And that is so cool. Except at the top here, if you see this, if you Zoom in, it just says Ally in Angular, where accessibility? A eleven letters Y in Angular. If you've ever wondered what Accessibility and Ally are they're the same thing. And that's great, except let's say I'm over here and I'm using a screen reader and I'm like, hey, what's this tab over here? And I'm tabbing through my options. I don't know what this is. I just noticed accessibility and angular and there's different things in here. So let's say I have like a store here, a description page that should be reflected here because these are different things that we're talking about and it's really inaccessible to have. Like let's say I open up ten of these, right. And I have different tabs that are on different pages if I have a bunch of local hosts. Right. Like they're all going to be the same no matter what I have open and no matter the status of them. And how are you going to tell the difference? So that is a huge pitfall of single page applications. And what we're going to do is we're going to use the router to define a page title in our routing module, we're going to navigate to our code, I'm going to search for my to do number four because we're on step four, I'm going to find, I'm going to find two files that I want to edit. Okay? So first we're going to go to our route module and we're going to look and we're going to say, okay, so I define my different components, right? So if it's at Shop, I'm going to load the shop component about location component. So pretty self explanatory, right? That maps exactly to these three tabs that are three routes here. And because it's a different route, I want a different title or at least want to reflect my different routes in my title. So I'm going to add some data to each of those to define a title. So if I go back to my code, I'm going to add one additional thing here, which is my data. I'm zoomed in so much you can't really see all this. Hopefully if I Zoom out, that works. And again, I'm just adding, let's see. So this is going to be about then I have data again, I'm going to pass an object, I'm going to define a title. And what I'm doing here is I'm saying, let's see. So what I'm doing here is I'm saying, okay, I have a route, I can lazy load it if I want. And I have some additional data that I want to pass to this route. And then I want to populate, I'm going to then go into my component and use that data to give a page title. Right. And so the data I'm going to pass per route is the title I want. So I'm defining a data object. I'm using the key name title. This is just what I've named it. Obviously you can name it something different. And then I'm going to pass this along and something really cool that's coming in a future version of Angular is we actually are cognizant of this. And after I wrote this code lab, I helped our team to find a way so that this will actually be known. So you're not even going to have to do the sex part. But for now, what you're going to do is we've defined all of our titles. So we now know what we want to do. And then in our app component, we now need to handle that title. Right? So we're passing along a route. We're saying, if we're at this route, I want you to load this component and I have a new title for you. And so now I want to change out. So if I go to my app component, once I save that, I'm going to say I need a title. So I'm going to start out by defining just like a basic title variable, just so that, let's see, I already have my title, so I already have my title just to find you my basic title. And then I'm going to create a constructor that handles that title. Right. So I'm bad at typing and doing so we're going to cut and paste and talk about these things code instead. Okay, so what I'm doing here is I've created a constructor that imports a title service. Right? And what I'm going to do in my title service is I'm going to say have a title. Okay. So I'm going to define a constructor. I'm going to create a title service that holds a title. Again, I have my router and my activated route, and what I'm going to do is on a net, I'm going to say, hey, can you get the title? And every time you get the title, what I want you to do with it is I want to take the router, I want to take the router and I want to pipe in and filter and say, hey, does my data have a title? Is the route that I'm at have a title? And if so, I want to give it that title, and otherwise I'm going to default back to the title that I've defined here. Right. And that's really all I'm doing. So if I save that and I go back and I don't need that anymore, I can see even without changing it. So this is like a great example, right. I can already tell without having to click on this that it's working. And specifically, I can tell that I know what I'm at. Right. So this is exactly what I'm talking about. It helps, obviously, for accessibility reasons, but it also helps me and I don't have any accessibility services turned on. Right. So by using my router to define a title, I now know that this is open to the Locate me tab, and that's super helpful. Again, if I have a bunch open and I'm looking for a specific one, I know that just to test it, we can click on our story and we can see it now says about we can click on Shop, we can see it says our shop. And so we now know that for each of the major pages we have a unique title service. So super helpful. If you're following along, feel free to give a thumbs up in the chat, or maybe comment if you have used a different title name or some questions. There a common question here is like, okay, so what's a good title? Like, how do we differentiate, right? They're all dumpling shop. Why doesn't it say dumpling shop? Great question. It could what you really want to reflect is whatever the difference is, you want to put first. So if you notice here I said about Accessibility angular. If we look up here, we see that I actually have a bunch of angular docs pages up. And this is a great larger example of that, right where we know that we're on the Angular docks. So we have Angular Dash, and then whatever the page I'm on is what's showing here. So let's say I have 400 pages of the Angular docks up. It would be super annoying if they all said Angular. Like, that's super unhelpful. And so it's really easy to know without even having to click into it. That like here I'm on the accessibility and Angular page, but here I'm on get started, right? Super helpful. So if you think about it, scaling up to something like, again, the docs page has something like 400 individual routes. It's really important that you're reflecting that information without forcing a user to go navigate to the page. Then navigate from all of the navigation features into here, which is going to be something like ten different tabs. So that's a really terrible experience for people using voiceover or things like that, as well as like, again, I don't use those in my daily navigation of websites, and I benefit from it. So just doubling down on it's useful for everyone. So again, this is a really great code snippet for doing that. But you're just piping and filtering your routes and I think it's quite fun to do. So that said, that's going to bother me that these are not. So let's do our next one, right? One check off the box. Again, we hit the highest possible thing. So again, if you do nothing else, go add this code snippet, think about your route. If you develop in an Angular application for your work every day and you're thinking about something that you can do to impact the entire website, this is a great low hanging fruit. Again, super small code snippet, big impact. So the next thing that I think has equally large impact is color. So this is one that our snapshot definitely found, right? So if I go to my application, I can see that it saw something with contrast. It said, hey, this contrast is terrible. And I can even test that and say, is it though and use my Inspector and get to it and say, oh, it is. It looks like my contrast is, which is far below the required amount. So let's fix that. Now, color contrast is super important because if you think about color contrast on the web again, even if you are a partially sighted user or have users with low vision, this is going to be super impactful. If I have everything that is like really light Gray on black or something that has really low contrast, it's super hard to read that. So think about it. Like, this screen right now has black text on a white background. There's really high contrast there. So it makes it really easy to read. But if I inspect this page and I change this to, let's say like color yellow, like I cannot read this code lab anymore, right? So if I was trying to teach this or if I was trying to look through and I had to highlight it to create enough contrast to read it, like this becomes completely unusable. So any work you did, all the great timing you did, let's say you maintain a really cool blog with a ton of really good information. If there's not enough contracts for people to read it, they're not going to be able to get all the information from your website. So in order to fix this again, we're looking at this accent color that looks wrong. So let's go in our code and look at what that is. So here we are going to look forward to do number five. So in our Style CSS, I'm using Angular Material in this application and I'm defining a bunch of color palettes with it. And so let me indent this to see this a little bit better. So it looks like in my light palette, which is where the issue was, right? So just for context, this like pink, red is our light theme and this like blue, green is our dark color palette. So with this light, it looks like I have a pink and I have a default and I have a lighter color and I have a text color and it looks like what is wrong is let's play with this and see what is going wrong here. So again, I'm just going to pick a bunch of colors here and see where these colors are coming through. So if you saw that with Angular Material, if you're not familiar, you define a color palette and you pass in the color palette variables. So if I go to my let's just do it. If I go to my Angular Material MPM node module and I go to my styles, I can see that in this palette. I'm exporting these color palettes. So I have like a red palette. I think I was using a pink palette. And so with my pink palette, I can call on any of these variable colors to refer to these text codes and they're defined by the material organization, which is the design system that Google relies on called Material. And this implementation is obviously Angular Material. And so I'm using my PayPal. I have a default. I'm using a $100. So that's going to be this color as my default. Again, not checks out. And then I think I have a lighter color, which is my 100. So again, I'm using these nice pinks. And then what I have here that's the problem is I have this text color, and I think it was 500. And so I was trying to say, like, anytime you just text, I want it to be this, but it's going to sit on like this, a 100, which is super close in color. Right. I don't know if you can see these little squares without zooming in, but they're really far away from each other. So I'm going to use 900, I think in the Code Lab, maybe I use something else. I'm just going to change it to 900 because I think that's safe and I'm going to save and I'm going to go back to my app and wait for it to build. And it loads. And yeah, there you go. So I can clearly see that now. Right. That's so much more visible than it was before. And if I want to inspect it, let's check. It looks like it still doesn't like that contrast. Oh, that's not great. Let's run our Lighthouse check and see if it agrees. So again, let's see. I just changed that single variable. Okay, so it's going to pass for our Lighthouse check. But it looks like maybe the contrast here is a little less happy. So 50% is pretty good. I would say that it's far above the Aria recommendation, but it looks like since I wrote this Code Lab, Chrome has gotten a little bit stricter in its recommendations. So we could even say, like, maybe I want to make it this darker. I don't have a darker color in my palette, but what I could do is make everything else a little bit lighter and see if that helps. So let's see. I could go to the 50 and just make it as contrasted as possible and see if that helps. Now, what's it think? Okay. Yeah. So if I do something really drastic like that, I can see that again. Maybe you can see this, maybe you can't. But if you're using your own inspect element, you Zoom in. I'm not sure I can Zoom in on the pop up tools. No, I can't. I'm so sorry. But if you Zoom in, you can see that really small there. The contrast tab is saying contrast 83% with a green check Mark next to it. So it's saying it's good with that accessibility. I'm going to go back to a 100 because I liked that better and it passed our Lighthouse check. But again, just something you'd want to check out of. What those contrast ratios are, and if they're matching, I am using Chrome Canary. So I will say that a lot of the tools I'm using are experimental and maybe pushing the balance of like these checks. But there's a bunch of cool stuff in Chrome Canary that I think is worth it. So that said, we fixed our contrast thing. So in general, what I would recommend in color contrast is obviously I'm using a color palette, which is super helpful because anything with the design system, I'm going to make sure that I can define in a singular place. Everything is relying on this default color. And these three colors are sort of explaining to my entire screen what our colors should be. And the more you have color variables. So using things like CSS variables and making sure there's like a constant singular source of truth for colors, make sure that if you've checked the color contrast in those colors that it's going to populate to your entire application. Some things you're going to want to do is when checking is you saw that I ran Lighthouse and I checked for the contrast errors there, and that's where it was reporting it. And then you also saw that in Chrome Dev tools, I use this inspection element and I was hovering over, for example, here, I can Hover and I can see that this black on pink gets a contrast ratio of 59% and a green check Mark. Or maybe even down here, this blue has a pretty good contrast as well. So again, just using that Hover and looking for the accessibility panel there and where it says contrast is going to be the best way to quickly see and check for that contrast. So we've done two things now, right? We've done our to do for step four and step five, unique page titles and color contrast. From here on out, we're going to get a little bit more semantic. So we're going to dig into a little bit more code, and maybe these issues are less like overarching, right? So page title affects your entire page. Color contrast affects your entire page. Now let's dig into like some very specific issues. So the next one we're going to dig into is using semantic HTML. Semantic HTML. You might be thinking like, why is this included in an Angular accessibility course? But the thing is, we're all writing HTML, like all of your Angular applications. Let's see if I search for spaces and anything in an HTML file. Look at all the HTML, right? So we're all guilty of writing HTML. Sometimes we don't write the best HTML, and I want to make sure we walk away from this writing the best HTML that we can. So let's look at our next step, which is step six. Now, step six is all about using semantic HTML. The idea here is like, if I have on this screen, for example, I have this thing here, right? It's like a big Div and I click on it. And you can see here that I'm logging something in theory, again, remember, like, maybe I navigate to another page. This is a make believe land in which you can click this magical button and it purchases our dumplings for us. But when I click it, you can see that it's acting as a button. But if I inspect it, what it really is is a Div. It's a Div with a click event and it's a Div with an H three, with a click event, which really isn't making use of semantic HTML to include Aria accessibility. So Aria accessibility is capital A, capital R, capital I, capital A. And those are accessibility roles that we're going to give to our HTML to manage accessibility for us, especially when interacting with things like screen readers and those types of accessibility services. So when we don't use semantic HTML, we completely bypass the web path towards accessibility for us and we essentially force ourselves to reinvent the wheel. And there's very few times, especially in something like as small as creating a button, that it's worth saying, I'm not going to use the button HTML. I'm going to create a Div to do it my own way. Better to use the button. Right. Another example of this is on our story page. You can see that I have all of this text and if I inspect it, I see that they're all, let's see, this is an H three, this is an H two, this is an H five and H six. And so all of these H numbers that I'm reading out our headers. And typically when you think about a page, it starts with like an H one, which is your big title. Right? So that's like Dumpling Shop or each one and we have some navigation items. And really what should come next is an H two, and then in each three. And then maybe it could go back up to an H two. And what you're thinking about here is like the structure of text where each of our headers should be subsets of one another. So it makes sense that it goes from the largest header. So a header one or a title down to our smallest a header six and some text inside of that. The more we confuse that, the more we confuse screen readers. Right? So screen readers like to read what level of header it is, and that conveys to our screen reader users where we are at within a text document. So if you jump from an H one down to an H six and back up to an H two, especially if you don't actually mean that in the context of it. So. Right. Like, if I look at this, who are we? Seems like one of the main questions. How are we different? Seems like a question at the same level. So in theory, those should be our headers and all of this information inside of it is probably detailed information that should be at a lower header number to convey that to users. So those are both things we're going to fix. So again, we're going to fix our headers to have a semantic ordering to use semantic HTML properly so that our screen readers can understand what's a header and what's description for those headers. And then we're going to go back to this purchase button and we're going to make it, we're going to make it a button because right now it's acting as a button and it's not a button. And the way we can tell that, again, I can tell you that because I've built this and I know that it's wrong. But I can also look at my Lighthouse and say like in navigation, I have this thing that says header elements are not in sequentially descending order. And that's exactly what I just described, right. Things that are heading should be ordered properly so that people don't skip levels. Because if I'm navigating this, I'm going to skip through to all my HQs and I'm going to get like some weird things read to me here. And then also it's not complaining here because it doesn't know that it needs to be a button. But if I went through on a screen reader, which I'm not going to do because it is going to essentially like try and screen read me out of this neat that we're in. But if I did turn on a screen reader by triple clicking my escape key, or you can go to voiceover preferences on your Mac or other device to figure out how to turn your personal devices on. And I navigated through to all of the options. The purchase wouldn't let me click it. It would just be like purchase this, right? And we want it to say purchase button, click space to click, right? So we want this to be interactive on a screen reader. So to do that, let's look at our code labs to think about what we need to change. So our first thing is in our Shop component, let's make this a button. So right now you can see this is exactly what I was complaining about. And this is what our linting caught, right? So if I look here, it was saying like, hey, in our Shop component, you're trying to click something, but nothing's going to happen, especially in a screen reader, right? This click event needs to be accompanied by a screen reader way for it to tell us what to do. So I'm going to take this code, I'm going to copy and paste it my new button. I'm going to get rid of that button. Say my new button is better and this is just a button. I'm using the matte flat button, which is a material flat style button. I'm giving it a color of primary and I'm giving it some classes just so I could style it if I wanted and then I'm giving it that same click event. But now I've given it in the click event to a button. And the benefit here is using semantic HTML, it's going to compile, it's going to know to add Aria roles and support to this. It's going to be able to handle it for screen readers. So I can save that. I can go back and I can see already the biggest indicator that that works is do you see that when I navigate over my mouse now can handle and shows that I can click that. And when I click it, there's an action. So just to show that difference again, if I go back to this button, when I Hover over the old button, it looks like I just can select text. Right. There's no indication with my pointer that I can actually click that or that anything is going to happen. Right? So if I go back to my new button, clearly significantly better. The other thing that I was going to do here is I was going to change my headers. I'm going to copy and paste for the sake of time. But in my about component, which again is to do number six, we're on, I'm going to replace all of these. It's the same text, but I'm going to replace them with semantic headings. So if you see here, let's look at the before and after. So if we look at the before and after, hopefully this is zoomed in enough for everyone reading my screen. You can look and see that. Before we had like H three H, two H five, H six H five, a Div, like what's happening here? And now if we think about it again, we have two H, two s, the two questions we're trying to answer and then everything inside of that is a paragraph. And we've added some styling so that we keep like a similar, cool, sort of funky stylistic look. But for screen readers, if people are navigating just through the headers, they can see that the two header sections I have here are my two questions. What is the shop you're on and why is it different? And now everything else is identified as something less than that. If you're writing a blog, for example, a lot of people have like blog apps and Angular. This is a great thing to think about. Like, do your headers make sense? Are they semantically in an order that makes sense? Are you using the correct semantic HTML Tags, like P, like buttons, anything like that? Right? A semantic HTML tag is like literally anything that has meaning when you're going in your HTML and you're writing like title, for example, is like semantic HTML. So we have fixed that. And let's look at that reload. I think it did. Now if I go to our Stories tab, it looks similar. But now we have two highlights. We have our two questions and everything inside of that is still styled, but it's more visually clear what the headers are there. And again, if I turn on my screen reader and navigated through my headers, I could see that. So for the sake of continuing to check our work as we go, we just did two things. We added the fact that this is now a button, clearly a button. I'm going to run my Linter again. Because remember when we did Ng Lit the last time it got mad at us for that quick event. And while it's linting, I'm going to go back and I'm going to rerun my accessibility check again and I'm going to see if it catches that semantic change we made. Right. Because this got mad at us for on our story page, the fact that we have those headers that didn't make sense. And look, it's no longer mad about this. So we're already into the green section. We've already fixed enough stuff that we're into the green 91 and we still have things to do. And if I go back to my linking, I see that all files are passing linting. So progress, right? Like semantic HTML got us pretty far. It got us into the green, it got us to a fully passing lending file. And there's still things that we can fix. So again, if you are just joining us and looking for the repository, it is all linked within our code lab. And we've now done unique page titles. We've now done color contrast. And we've added our semantic HTML. And now let's look at our controls. So the next thing we're in a fixed is something that is angular material related. So if you look at our shop here, we have something that's pretty complicated actually, especially for accessibility services. And that's the fact that we have nested controls. So for example, I have some fillings here that I'm focusing on. Let's just Zoom into our fillings to focus on this. Ignore my dumplings. Really don't like to be zoomed in this aggressively, but I do for purposes of accessibility of you seeing my screen. So I have all my toppings here, right? I have meat and vegan. I don't eat meat. So I added impossible burger meat. But if you do, you can order chicken, don't worry. And so I allow you to click all these things, right? And there's some cool stuff here where I can click vegan and get both if I unclick box way, it knows that it's not the fully vegan one. I can make some fun selections here, right? But nested checkboxes are really not the best practice for accessibility. And this happens a lot, right? This is a pattern. Maybe designers come to you with a lot for your different applications in writing. And I would highly recommend you push back and think about like, hey, I attended an accessibility workshop and I heard that this wasn't a best practice and let me tell you why. So it is very hard when you're navigating through something like nested checkboxes with a screen reader to understand the nested complexity. So let's say I have everything checked and I navigate from vegan into boxway and unchecked tofu it is hard to then reflect to users without navigating back up that they've unchecked the vegan selection. So when you have a nested structure like this that has nested use cases, it's hard to convey. Again, if I have navigated, let's say selected vegan and then navigate to Boxwood and tofu then meat, then chicken, which is the correct tab order, and I get to impossible meat and I unselect impossible meat, you're going to next tab to quantity and you're never going to be able to reflect to users that they've unselected meat. So really not a great best practice. If there's a way to do this that doesn't require nested checkboxes, we're going to prefer that and we're going to prefer that because it's more semantically sensible and we want things to be as simple to use as possible, especially for cognitive disabilities and things like that, but also because it's going to create a better UI. So even if I look at this from afar, I don't really understand what's happening here with my vegan versus meat, right? Like impossible meat is vegan anyway. So maybe that should be up here. But also when I Uncheck chicken, is it really not a meat one? Because I still have some meat in there. There's a lot of questions you could ask and we've really made things more complicated than they need to be. So let's change our controls to make them more accessible. The other thing is that by simplifying menus we're making them more navigable. And the other thing is that we're going to use Angular material to ensure that the check boxes we create have built in accessibility. So this is where I do a subtle plug that using something like a component library is the best way to get accessibility, especially for Angular material, which is Google's component library. And that's because we really care about accessibility and make accessibility a priority zero or the top priority. So we want to make sure that we're delivering the most accessible components to you all. So if you are ever looking for like hey, I want to create some check boxes and I want to do it really quick for my application and they need to cancel use a component library using the other materials because you're going to get accessibility out of the box. So in order to do this we're going to replace our checkboxes with material check boxes. And to do that we're going to go to our component and we're going to change how we add these things. So we are now on to the number seven. I've marked these things just to make them a little bit more sensible for me and we're going to go here. So in our shop component TS again, this is the component file where we are defining all of our fun things for navigation and we are going to add our flexible controls. So we are going to change our feelings to be instead of an object with a set of boolean. So again, this was maintaining like the filling variable was saying, like, is this box way true or false? Is this tofu true or false? And I was passing that to that check box. Now I'm going to have a list of strings and these are going to be a list of options of what's out there. And in doing so, I've also leveled up our options a little bit. If you'd like to level them off to something you like, that is different. Go ahead. I'm super into Chili Crunch right now. There's a bunch of really good chili crunch in the local supermarket. So I have added some chili crunch as an option. I've also added some tofu I kept it impossible meat. Let's get rid of that. Maybe let's make it just like spinach. Extra spinach. So I've changed my feelings to my list of strings and then I've also created a selected filling variable. And this is going to maintain what is selected and I'm going to keep everything else. Now in my faux purchase. I also want to make sure to change how I print my faux purchase since I changed my object of filling to be a little bit different. So I just want to change how I select my flavor by going through why is it not about this? There you go. Sorry, I'm just fixing my single quote. Yeah. So I'm just maintaining that my flavor is going to be whatever is in my selected object from my array here. So I have to find that my array of feelings. I have four beautiful flavors. I'm maintaining a list of what is actually selected from my filling choices. And then every time I make that purchase, I just want to make sure that I'm iterating through that list and adding them so that when I print it knows what to do. So now that I have a new list of what my fillings are, I want to go in and I want to change my object and I'm going to use map selection list. So in my component object in my HTML, I'm going to get rid of you can just collapse even this really long ul list. I'm just going to delete it. And we don't even need to look at how ugly that was. Instead, I'm going to add in a cool map selection list and you can copy this code all from right here. But let's talk through it. So my map selection list is my material selection list. This is a list of things we can select. I'm going to give it an Ng model, which is going to be a model of what I have selected. I've handed it my selected fillings variable, which again is a list of strings. And I've given it an Aria label so that I can explicitly say, hey, when you get to here, this is the selection list of my dumpling fillings. And that's what's going to be read to screen readers. And then for each of my options, I'm going to ng four and iterate through all of the feelings I have to have a flavor, give it that value, some color, and just give it that text. If I select that and I save, I should be able to go here. And yes, it is reflected. So if you remember, we used to have some nested controls that didn't really make sense. I was like doing that weird meat vegan thing. And now I just have four checkboxes of some extra flavors, my extra spinach of new flavors of dumplings. So I've reinvented my dumpling flavors and I've made it more navigatable. That is a hard word to say. Navigable. So it's more navigable. It's also more cognitively intuitive for users to understand what's happening. You're selecting your fillings, you can select more than one. There's no nested dynamics of what that means. And they also have some styling. And I was able to give it an Aria control or Aria label so that when it's read to users, there's context for what they're selecting. And so that's really great. So that once again, this form doesn't have associated labels. So let's rerun and see if that fixes that. And we got rid of that weird form error here because it was saying like you haven't given any context, right? You're making people navigate through these weird nested controls and they're selecting fillings, but like fillings for what, there's no context. So now we've used angular material, we've used built in components that have accessibility included. And we've used the map selection list and Aria label to ensure that we're providing context and a clear, more intuitive way to select these things so that when you're navigating through the screen reader, you're not getting stuck in a weird, like, context hole of not knowing where you are. So we're at a great point. Let's just do a check again, that was creating selectable controls of material. And let's just keep checking on it. Looks like we are at about an hour. We have halfway to go. So I'm going to speed up a little bit. But luckily these next ones are pretty easy. So the next one is super similar. Provide controls with Aria. So we've already talked about Aria, but the screen reader isn't reading the slider values. And if I go to my Lighthouse score, if I go to my Lighthouse score, this is exactly what this is saying here, right? Like my input doesn't have an accessible name. This is an Aria issue. And we want to improve our usage of Aria. So what we're going to do is we're going to say it's yelling about my slider. Very specifically, this error is saying like this Matt slider doesn't tell me what it is. And without that, I'm going to get stuck in moving the slider. And it's not going to tell me what it is. And a really simple way to do that is to use Aria. So I'm going to go to my shop component and I'm going to take my Mac slider. And very simply, I don't even have to do any of these other things. I have all this stuff here. All I'm going to do is give an Aria label in my Map slider. I'm going to use Aria label. I'm going to give it some text that explains what it does. So here I think the example I gave was dumpling order quantity, slider dumpling order quantity. And I don't even have to say slider. Right. Because it's going to read its role. So an Aria role is already going to be applied on this to say that it's a slider. So it's even a better practice to not include that role. Right. Like I'm going to correct my code lab. A better use is to just say when you think of Aria, we need to read role value and then action or description value role. And so the description here is dumpling order quantity. It's role is going to be a slider. It knows that already. And then the action is going to be like entering the slider and all of that is going to be handled by the voice screen reader. So we've added that. And if I go back, I've saved that, right. If I go back, I run because I fixed it. Yeah, cool. So we're at 100%, which is great. And I'm going to push that even further. Right. Because why not 110%? No, really. So we've already fixed everything that is automated. And this is exactly where I said you can't automate all your checks. So this runs again. We ran our lender, everything passes there. We still have manual testing. Right. We can still push this and say, I know that I've fixed everything that an automated check can fix, but I can still do more. So Aria controls color page titles. Those are all things that are automated. But there's more you can do. And so something that I'm really going to encourage everyone to check out is the CDK accessibility package. So this is where you're going to run. Sorry. This is where you're going to navigate to material. Angular. Io. And you're going to go in and say there's this thing called the CDK. The CDK has something called accessibility. And this is an entire package built for angular. And you don't have to use Angular material to use this that is specifically focused on accessibility. So this is things like there's list key management, because that's important or focus trap. We're going to talk about that. But there's all these tools for things that we recognize that when writing components, if you're writing your own components, you're going to have to manage these things and there's an Angular specific way to manage it and we want to provide you the tools to build better components so that if you're like building an enterprise application or you're maintaining an open source package or something like that that has anything to do with the UI, you should know about this page. So again material, docs, CDK and the ally one accessibility. So to add that we're going to go to our app module and we're just going to make sure that we've added this accessibility module. So if I go to my app I want to make sure that again I add this import, I'm going to import it from the right place and then I'm going to take my module and I'm going to add it to my imports. Actually I like alphabetical or semi alphabetical. I guess somehow these things have gotten slightly unalphabetical. But it comes first, I'm going to import it and now you're not going to see anything. But if I go to my Ng terminal you can see that I just recompiled it noticed that there was a new module it needed to bring in and so it did. So and now we're going to make use of it, right? So what we did here is we just added to our module. If you're familiar with Angular applications, we added a new module that has the ability to ensure that we can make use of all of these things. So again I'm looking at these documents, I'm like wow, there's some cool stuff in here that I want to use. In order to do that we need to bring in the module. We just did that. Now let's go use the things. So ten focus shop. I just talked about this, right? So I just said hey I noticed here there's this thing, let's see there's list key management, there's live announcer, there's focus monitoring and there's focus chat. But what's focus trap? Well the CDK focus trap or chat focus directive is a way for us to ensure that when we're tabbing through our elements with something like a screen reader that we're trapping the focus to where we want. So really great example of this is if we open our shop we've changed the color a few times, right? So we said like hey I want five box chili crunch tofu mushroom dumplings. I like this gold color of this wrapper, let's make them plum. And this right here is a modal that I'm opening. And so if I was navigating with the screen reader I would want to make sure that the screen reader knows when I'm navigating within this to trap focus before I apply color. Right? So let's say I'm in a screen reader and I open my wrapper color and then I'm like navigating through this and somehow I'm like on this home button up here and I'm trying to click it. That makes no sense, right? But for a nonsighted user or somebody who is using a voiceover service, you don't have the context to understand that you've escaped this modal that you're supposed to be trapped in. So the best practice is like, if a modal is open, focus should be trapped to that so that users can understand that there is an action that has to occur to navigate. Outside of that, you're not really in a place to select fillings right now, you're selecting your wrapper color. Let's go with this. Like, nice, we're going hot pink. So now that we have our hot pink five fun dumplings, let's look at how to add focus drop. And this is going to be super easy. All you're going to do is add the directive. So a directive in Angular again is sort of like a control that you're adding to something. And all we're going to do is use this attribute called CDK focus initial and add it to our material context. Now we're mostly just doing this to show what it would be like because since we are using Angular material, our focus is already going to be tracked. Let's see, where is this? But in our Color Picker dialogue, let's look at this. So in our Color Picker dialogue HTML, we have a selection list. Again, sounds familiar, but this time we want to make sure that the focus is trapped. So all we're going to do is add CDK focus initial to ensure that we're focusing on the selection list when we first open the dialogue so that when we open the dialogue, we're not accidentally focusing on like again, this home page or like our shop, because our focus really should be within this. If we think about our other Mat selection list, let's think about our other Matt selection list. This wouldn't make sense for using that CDK directive, right? Because here we don't want to chop focus here. Again, this list of fillings. Once you enter this, you can navigate out of it. There's other things on this page, but here, that's only on the page. Right? So we want to add that directive. So if we go back, we've added the CDK focused initial directive to our selection list. And let's save and again, nothing's going to actually show up for us, but in theory, we now know that we're chopping focus when we have that behavior. Moving on, step eleven, we're going to do another CDK thing, which is using Live Announcer. So Live Announcer is the idea that when it changes made to the page, we want to reflect that to Voiceover. So for example, a great example is again, I really like my color picker. Let's say I navigate through and I change to hot pink. Okay. Voiceover does not like my meat. Anyways. Obviously you can't hear my voice over, which is why I'm not presenting it. But if I was to inspect and go into this module again, Voiceover is going to read all of these things. And let's say I click light green and then I apply color. There is no notification to the user that that successfully happened. Right. So let's say it failed. Or let's say, like I accidentally selected gold and I clicked apply color and then I didn't know that I changed my color and I went to purchase them. We want to make sure that when a user exits this modal, they understand the selection they just made and they're notified of that change because there's a visual change happening on the screen. So anytime there's a visual change happening on the screen, a great example would be let's say I had a form and I tried to submit a form and a bunch of errors happened. Obviously there's a red arrow. The error message is red. But for people using screen readers, they're not going to know that all those errors have appeared on the screen because they're not highlighted. Especially, let's say there's like ten errors. You can't highlight all of them. So the best practice is to announce those to the user. And there's a few different ways to do that. You can do that politely, you can do that more urgently. But all of that is going to be done using the Live and answer. So if you want to recreate that, there are steps to identify the issue. Again, I cannot have my screen reader read to you, unfortunately. But to fix this, we're going to add the Live answer to our color picker. So we're going to our code step. I think we're on number eleven. Okay. And in our component, let's first make sure that we notify the change. So first, in our dialogue component, in our constructor, we're going to change our constructor to have a reference to the live announcer. I'm going to copy and paste this code. I'm going to give it, and I'm going to make sure that I import my Live and answer and some data. There you go. Okay. I want to make sure I imported the things I needed to add. Cool. So what I'm doing here is I'm creating constructor. I already have my dialogue reference, but now I'm just injecting to make sure that I know what data is being selected from a color dialogue data. So again, I want to make sure I know which color was just selected within my color picker component. And then I'm going to use this live announcer thing. So remember, we imported the module CDK Ally. Now I'm importing my live announcer from my CDK Ally because I want to use it, because I'm going to announce something. I'm basically a sports announcer at this point, and then I'm going to create a change color. Now I'm going to do one other thing, which is before I close my component. So before I use my dialog ref to close because I've made a color if I've changed my color. So not if I've exited, because I don't want to do anything, then, right. There's no change to reflect. But if I've changed my color, then I'm going to go to my Live Announcer object that I've already constructed from Live Announcer. And I'm going to use the announce API call to say I've selected a color and I'm going to look at whatever color I have as an object and I'm going to make sure to announce that. Right. And that's it. Right. So it's the Live Announcer dot announce. Super intuitive if you're interested in this. Again, I can go to the Live Announcer docs. I can say, hey there's, Live Announcer. And I can go to my API reference to make sure that I understand what is there. Oh, look, my main method is announced. And now if I were to go and do that again, remember, anytime I'm clicking a new option and I'm applying the color and it's emitting that change, I'm also going to announce to my screen reader, Select Color Opt Pink, or Select Color green yellow. Right. So that I can notify users, even if you're not visually seeing a change on the screen, that a change was made. So cool. Now the live announcer, we've done that. We can verify. And there's one last change I want to make, and then we'll wrap it up. And this one last change is one more thing in that CDK Ally package. And this is High Contrast Mode. And so High Contrast mode. I don't have Windows Open right now, but it's a Windows specific feature called High Contrast Mode. I think that there are plans in the Chrome organization to do something similar. And this is the idea that you can change the appearance of all of your applications to dramatically increase contrast. So in High Contrast mode, very typically, instead of like, pink and red and blue and all these colors on screen, it would just be white and black to create the highest possible contrast. So again, we already did. Like, I'm checking all these things for contrast ratios. I'm seeing, like the 50s, the 60s. We want to make sure everything is essentially 100% right. It's the highest possible contrast. This is great for users who may be prone to migraines. I have team members that use this because they get headaches if they look at screens too long. Right. Like, we all live in a world where we stare at screens all day. High Contrast Mode is super useful for that. And those are disabilities, right. They may not be thought of in the same way as more typical disabilities, but they are just as valuable to ensure that you have an application that is thinking about those use cases to make sure that everyone is able to use the services you're creating. So High Contrast Mode is super cool. Again, it's on Windows, and we have something cool, which is the High Contrast Mode detector in the CDK Ally package. And so what you're going to do here is you're going to actually go into CSS and this is super rare, right? That I feel like you can make accessibility changes purely out of CSS, especially that intelligently know that this thing happens. And so what we're going to do is we're going to import our CDK ally, you don't need the Tilde anymore if you're following along here. But that is a recent change to version twelve and then we're going to add some new CSS. So what you're seeing here is if I go to my purchase button, I can add that when I have a CDK High contrast mode which I'm detecting using again, this import that I just made from the CDK ally. I now have access to a new mix in or a new media query to say when CDK High Contrast is on for my button, let's use that as a use case and let's make it look really high contrast. So let's make the background color the lightest possible and let's make our outline super thick. So like the thickest possible. And we're just going to do the same for dark mode just to make sure that both teams have that. Because I think that's important. And now let's go to our application and see what that looks like. Why is it mad? Let me try and rebuild a fun thing where rebuilding might save us. Or I will say it got through twelve steps before I ran into an issue. So I think that's kind of impressive, all things considered. Yeah, it does not like that import. Do not know why it does not like that import. Let's think about okay, well, I have something I can do. Remember how I said at the end you can get check out I have all my changes and that's why. So it looks like we've actually changed it. So you just import the CDK, not CDK, ally. So I should go and change my code lab since that changed in version 13. So instead of this import statement, you're just going to remove that Tilde and remove the accessibility reference. And this is all going to be within CDK as part of the most recent version. We were more intentional about elevating how you import things like that. So if you're interested in that, feel free to tweet me if I forget to change the code lab. Bonus points. So yeah, you can see that in high contrast mode. In high contrast mode this would be applied, right? So CDK highcontrast is how we're going to reference this. And again, I actually think this Code lab is even more incorrect because CDK High Contrast mode is for version twelve and below and we've now changed the reference to CDK High Contrast just if you're following on along specifically and main should reflect version 13 version of these things. The Code lab just is version twelve and below. So I need to make that code change. But I did get to the very end of this code lab before I ran into this. So I'm going to take that as a success. So since I'm not in high contrast mode, I just want to show what that would look like by removing that media query just so that you can see. And so that is a great example of what high contract looks like. We're still using a little bit of hue because we think it's fun. But an even better practice would just be to make it white, right? Like the highest possible contrast. And we could even make this even thicker, right? So making sure that people have the highest possible contrast there, we could make the text even larger, something like that. But that is going to visually read as a very clear button without having any sort of visual clashing. Or this green could be like really jarring on certain eyes. So I want to make sure to respect that in high contrast mode, especially for those users, by providing some styling specific to that. So again, this is a super cool mix. And I think it's really cool that the CDK has the ability to find these things, and it's very cool to be a part of the modern web doing that. And with that, I think that we have ten extra minutes. So I just want to say Congratulations. So if we think about it, remember we successfully should not have that open. We successfully went from a very inaccessible application to a completely accessible one, right? We ran Lighthouse to generate our score. Again, we did this awhile ago. Pretty sure it's still going to be at 100%, but let's just do it to check. It feels good to give us some paths on the dock for this. So yeah, so we got 100% there. Remember, we Linted with our Lint rules that we added. I'll run it again just to prove how good we are. So we did Linting. We use Lighthouse to check our accessibility. We also talked about how to manually test and for those of you following along, hopefully you have checked out how to turn on voiceover and do these things. And then we went through eight different things, right? So we talked about why single page applications are great, but why we should think about unique page titles and how to add them, especially using the Angular router to do so, and then manage those routes in our app component at the highest level. We talked about how to check contrast ratios and add them, especially when maintaining a design system like Angular Material to ensure that we only changed one line of code. Right. We just changed the color of the text to make sure that that was accessible and the entire app suddenly was passing for contrast. We talked about semantic HTML, using buttons, using headers appropriately. We talked about flexible controls, and how to make sure that instead of confusing nested checkboxes, we were using a more intuitive more cognitively dissonant version of these things. We talked about Aria labels and how to add those to things like our sliders to ensure that we were defining the Aria input so that our Aria was meaningful so that if I'm navigating this thing, I can successfully buy my dumplings. And then we also talked about CDK Ally and some different things, including Focus Chop, Live Announcing and High Contrast Mode and CSS. And so with that, you can count how many different commits you have. But feel free to again revisit this code lab. If there were specific steps that were tricky for you, feel free to open issues on the GitHub repository or tag me on Twitter at Twersky. It's my last name, but instead of the Y and E, and I'd love to talk about all these things with you. Yeah. And let's see. I know that the chat has been pretty quiet, but if you have any questions, now is the time to throw them. I know we have seven extra minutes, but I just want to wrap up and say thank you. Again, it's really cool to see people care about accessibility, especially with Angular. You have a huge impact by doing these things. So even just running the core websites to see where you're at now and make little adjustments is like a great place to start. Let's see. There was also a feedback feedback link sent out in the chat, so please go ahead and add it there. And again, you can find me on Twitter. I'll throw that in the chat as well. That is the easiest way to get a hold of me. Yeah. Let's see. I see some questions. Can you please help me with Debugging with Chrome Dev tools? There's some really great resources for Chrome Dev tools. If you even go to just Codelabs developers, Google.com, there are some great code apps there that are on like Dev tools. Let's see. Oh, I spelled it wrong, but if you spelled it right, you would get more. Yeah. So there's some great videos there. There's also some videos on the Angular YouTube for that. Debugging is like a super broad question. If there's something specific to acceptability that you want me to answer, feel free to have that in the chat. How is Angular app architecture different from other frameworks? Angular is super opinionated, but it also has a lot of solutions out of the box. Right. So Angular, if we look at our application, each of my components, I have a very familiar structure where I have HTML, CSS or SAS in this case, and then the component. And the component is where I have all of my logic, the staff is where I have all of my styling, and then HTML is where I have the actual structure of that, and that's going to be the same no matter what application you go into. And so it's super familiar. Right. So it's really easy to onboard to a new application even if you're not familiar with the actual code you're working with. And it also has all these things out of the box, right? So we have the ally package, we have all these things versus in other frameworks you would be bringing in third party libraries which is also great but just a different approach. So angular sometimes is thought of as a slightly larger solution, especially for enterprises. But really what that means is instead of putting it on your hands to say like I need accessibility, I need to go find an accessibility package and bring that in and make my app larger. By doing so, we say like hey, at its core you need accessibility. We're going to give that to you and we're going to say that it is going to be a little bit larger out of the box. But that's because out of the box we also are giving you solutions to these things. Let's see, a recording will be provided. Suppose I need business logic. Could you share there's a question about business logic resources for debugging, it looks like so Chrome Dev tools is mostly for styling and visual changes, right? All of these panels really are about debugging like visual things. If you're talking about performance or things like that and you're developing with angular, I highly recommend you download angular dub tools which does have things like a profiler where I can record my change detection cycles and then debug for performance, right? So like let's stop that. I can see that somewhere back there like that didn't do so well. My app component was making sort of a costly change. So if you want to know more about this, we have entire videos about this angular. Io backslide and depth would be a great way to start debugging for performance. For business logic, you're going to have to do a lot of that debugging yourself. Lighthouse is what I use. We've talked a lot about Lighthouse tonight, but yeah, I just want to say again, we have two minutes left but thank you so much for joining again. Feel free to reach out on Twitter. I know a recording of this will be sent out and you have all of the code to play around with. So if you are interested in any of the specific recommendations made again, the code lab is online and available at all times.