[MUSIC PLAYING] EMMA TWERSKY: Hi, everyone. My name is Emma Twersky 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
more accessible Angular applications. So we're going to spend
the next hour, 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
backslash Angular-a11y, and I'll throw that
in the chat as well. And I'll throw that
a few more times as I see people coming in. So that's we're going
to head 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 of how do I code with only one
hand, especially if it's my left hand? Like, 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, or 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 a 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 y'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 started-- oops, I'm not logged
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 setup,
I am assuming you already have Angular npm installed. You have everything
up and running. But if you are struggling
to do anything there, please make sure you can go
to angular.io backslash start, and that will get started. So if you're having
any dependency issues with 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 codelab, 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. You're going to want to make
sure you have npm installed. I've already done this, so
hopefully it's all cached. Doo-doo-doo. 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 fun lobsters
in the background. I highly recommend having a cool
computer background to look out for while you're building. And the super exciting thing
about this-- ooh, compiled successfully-- the
super exciting thing about all of 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've built, right? So if we go to our local host,
4200, this is our repository. And we are currently on,
again, if I just check out my Git branch to go
back to my terminal, I can see that if
I do git 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 Main 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 we're 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 codelab. 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 13 dumplings. So this is like a
custom dumpling website. I know a lot of
holidays are coming up. Maybe you want to order some
really fancy, special dumplings for a loved one. So we get to pick what
fillings 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 dye your dumplings to a series of rainbow colors. So for example, let's
get some sky blue chicken and bok choy dumplings. And you can click Purchase. Obviously, that is 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 OK, 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 a cool, fun application. I think it looks kind of cute. But we recognize it's
not accessible, right? Like 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 am going to say, my designer told me that I need
to be able to go to my website, select any type
of dumping 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 in 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. Like something that's really
important in accessibility is that when you are read
the choices on a slider, that you understand
what those mean. So there's a cognitive
aspect of that. And 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 tests, 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 I also have
the Angular DevTools. My favoritism 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. Oop. And 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. Today we're just talking
about the desktop or web accessibility, so
for the sake of time. But there's some other
cool stuff in Chrome if you want to do it. Anyways, so we got our report. We got 87. So that's not bad, right? Like, 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 to-do lists. Then the third type of check
that we're going to run is linting. And so this is where in
Angular, I'm using ESLint, and I'm specifically looking
at the Angular ESLint rules to make sure that
I can lint 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 10 different checks
here in my ESLint rules. So if I go to the .eslintrc
JSON file, I can see those, and I've set them all to
2, which means an error. Which means if I have lint
checks on and I run linting, it's going to run an error. And see, these are the 10
things that lint can do. And this is even more
than the usability of what's on the screen,
so things like color, 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. Whoops. 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 lint rules, and I can see that
I have, again, 10 rules here set to those
things for my ESLint rules. So if you're using
ESLint, and these are also available in other
linting, it's going to be the same set of rules. Just a slightly
different declaration. For 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. And there's an error. Right? And so the 2 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 some as a 1 and that's going
to throw a warning. 2 is going to be an
error, and depending on your CI/CD
pipeline, it's going to stop you from building. But we want that, right? We want to write the
best code we can, and this is going to
push us to do that. And so this lint is finding-- what's it 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. So 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 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 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 "a11y in Angular" or accessibility a 11
letters y in Angular. If you've ever wondered what
accessibility and a11y 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 know it's
accessibility in Angular. And there's different
things in here. So let's say I have a store
here, a description page. You know, that should
be reflected here, because these are
different things that we're talking about. And it's really
inaccessible to have-- let's say I open up
10 of these, right, and I have different tabs
that are on different pages. If I have a bunch of
local host, 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. So in our routing module,
we're going to navigate to-- in our code, I'm going to
search for my TODO number 4, because we're on step 4,
and I'm going to find-- oops. I'm going to find two
files that I want to edit. OK. So first, we're going to
go to our route module and we're going
to look and we're going to say, OK, so I defined
my different components. So if it's at shop, I'm going to
load the ShopComponent, about, About, locate,
LocationComponent. 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 I 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 still works. And again, I'm just
adding-- let's see, so this is going to be About. And 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, Locate Me
dash a11y in Angular. It's hard to type and talk. So what I'm doing here is I'm
saying, OK, 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 codelab, I helped our team define a way
so that this will actually be known. So you're not even going to
have to do this next 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
AppComponent, we now need to handle
that title, right? So we're passing
along the 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-- let's see, let me
move these around. If I go to my AppComponent, 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-- oops. Let's see. Oh, I already have my title. So I already have my title. I'm just defining
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 this code instead. OK. So what I'm doing is I-- oops. Let's do that. What I'm doing here is I've
created a constructor that imports a titleService, right? And what I'm going to
do in my titleService is I'm going to say, have a title. Oops, that's not-- OK. So I'm going to
define a constructor. I'm going to create
a titleService that holds a title. I'm going to-- again, I have my
router and my activated route. And what I'm going to do is
OnInit, 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. And that's really all I'm doing. So if I see that and I go back. And I don't need that anymore. Oops. I can say oops 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,
OK, 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 dash Accessibility in Angular. But 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 doc 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 Docs 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 here I'm
on the Accessibility in 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 what, 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 10 different tabs. Right? So that's a really terrible
experience for people using VoiceOver or things
like that, as well as, 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 typing
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 tabbed. OK, whatever. 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 routes. 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, mm, is it, though, and use my Inspector and get
to it and say, oh, it is. It looks like my
contrast is 20%, 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
really light gray on black or something that has
really low contrast, it's super hard to read that. So think about it. 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, color yellow, I cannot read
this code blob 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, this becomes
completely unusable. So any work you did, like
all the great typing you did. Let's say you maintain a really
cool blog with a ton of really good information. If there's not enough contrast
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 into our code
and look at what that is. So here, we are going to
look for TODO number 5. So in our styles.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
pink red is our light scheme and this 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 those
color palette variables. So if I go to my-- here, let's just do it. If I go to my Angular
Material NPM node module and I go to my styles, I can
see that in this palette, I'm exporting these
color palettes. So I have 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 hex codes and
they're defined by the Material organization, which is the
design system that Google relies on called Angular-- called Material, and
this implementation is obviously Angular Material. And so I'm using
my pink palette. I have a default.
I'm using A100, so that's going to be
this color as my default. Again, that 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-- yeah, it was 500. And so I was trying to
say anytime there's text, I want it to be this. But it's going to sit
on this A100, which is super close in color, right? Like 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 codelab
maybe I used something else, but 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. Ooh, looks like it still
doesn't like that contrast. Ooh, 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. Ope, OK. 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 is far above
the ARIA recommendation. But it looks like since
I wrote this codelab, Chrome has gotten a
little bit stricter in its recommendations. So we could even say 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. Oh. Let's see. Yep. Now what's it think? OK. 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 am so sorry. But if you zoom in, you can
see that really small there, the Contrast tab is
saying Contrast 83% with a green
checkmark next to it. So it's saying it's good
with that accessibility. I'm going to go back
to A100 because I liked that better and it
passed our Lighthouse check. But again, just
something you 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
bounds of 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 contrasting. 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 a 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
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. Something that you're
going to want to do is when checking, 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 DevTools, I used this inspection element
and I was hovering over. So for example, here
I can hover and I can see that this black on
pink gets a contrast ratio of 59% and a green checkmark. 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? So we've done our TODO
for step 4 and step 5-- 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 overarching, right? So page title affects
your entire page. Color contrast affects
your entire page. Now let's dig into some
very specific issues. So the next one we're
going to dig into is using semantic HTML. Semantic HTML, you
might be thinking, 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 6. Now, step 6 is all about
using semantic HTML. The idea here is 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 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 H3 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 rules 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's
path towards accessibility for us and we essentially
force ourselves to reinvent the wheel. And there's very few times,
especially in something 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 and 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 H3, this is an H2,
this is an H5, an H6, an H5, right? And so all of these H
numbers that I'm reading out are headers. And typically, when
you think about a page, it starts with an H1, which
is your big title, right? So that's like
Dumpling Shop, our H1, then we have some
navigation items. And really, what should come
next is an H2 and then an H3, and then maybe it could
go back up to an H2. And what you're
thinking about here is 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 1 or a title, down
to our smallest, a header 6 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 H1 down
to an H6 and back up to an H2, 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 detail
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-- well, 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, huh, 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 headings
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 H2s and I'm going to get 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 try and screen read me out of this
meet that we're in. But if I did turn
on the 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. Div." Right? And we want it to
say "Purchase button. Click Space to click." So we want this to be
interactable on a screen reader. So to do that, let's
look at our codelab 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 it was complaining about. And this is what our
linting caught, right? So if I look here,
it was saying, 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 in my new button. I'm going to get
rid of that button. It'll say my new
button's better. And this is just a button. I'm using the mat-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'm going to [INAUDIBLE]
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, and 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 worked 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. There's no indication
with my pointer that I can actually click
that or that anything is going to happen. 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 TODO number 6 we're on, we're
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 H3, H2,
H5, H6, H5, a div-- like, what's happening here? And now if we think
about it, again, we have two H2s, 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 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 blog apps in Angular,
this is a great thing to think about. 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 literally anything that has meaning when
you're going in your HTML and you're writing-- title, for example,
is semantic HTML. So we have fixed that,
and let's look at that. Doo-doo-doo. Did it reload? [INAUDIBLE] I think it did. Now if I go to our Story
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 turned
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 lint the
last time, it got mad at us for that click event. And while it's linting-- yeah. 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. Because this got mad at
us for on our Story page the fact that we had 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 linting, I see that all files
are passing linting. So pretty good progress, right? Semantic HTML got us pretty far. It got us into the green, it got
us to a fully passing linting 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 codelab and we are now on-- 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 going to fix 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 Bok Choy,
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 you're writing, and I would highly recommend you
push back and think about, 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
Bok Choy and uncheck 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 I selected Vegan and I
navigate to Bok Choy, then 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 sensical and we want things
to be as simple to users 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 like look
at this from afar, I don't really understand what's
happening here with my Vegan versus Meat, right? Like, I mean, Impossible
Meat is vegan anyways, 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 there. 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
navigatable, or navigable. And the other
thing is that we're going to use Angular
Material to ensure that the checkboxes 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 0 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 checkboxes and I want to do it really
quick for my application and I need a scaffold,
use a component library. Use Angular Material,
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 checkboxes. 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 TODO number 7. I've marked these things just
to make them a little bit more sensical for me. And we're going to go here. Oops. We're going to start-- yeah, we're going to start here. So in our shop.component.cs-- again, this is
the component file where we are defining all of
our fun things for navigation. And we are going to add
our selectable controls. So we are going to
change our fillings to be, instead of an object
with a set of Boolean-- so again, this was maintaining-- the filling variable was saying,
is this Bok Choy true or false? Is this Tofu true or false? And I was passing
that to that checkbox. 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
up 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 the Impossible Meat. Eh, let's get rid of that. Maybe let's make it just
like spinach, Extra Spinach. So I've changed my fillings
to my list of strings. And then I've also created
a selectedFillings variable, and this is going to
maintain what is selected. And I'm going to
keep everything else. And then now in my
fauxPurchase, I also want to make sure to change
how I print my fauxPurchase since I've changed
my object of fillings to be a little bit different. So I just want to change
how I select my flavor by going through-- oops. Why is it mad about this? Oops. There we go. Oop. Did I get that? Maybe I didn't. Oops. There we go. OK. Sorry, I'm just fixing
my single quotes. Yeah, so I'm just
maintaining that my flavor is going to be whatever is in my
selected objects from my array here. So I've defined my
array of fillings. 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
mat-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. And instead, I'm going to add
in a cool mat-selection-list. And you can copy this
code all from right here, but let's talk through it. So my mat-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
selectedFillings 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 a 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 4 and
iterate through all of the fillings 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,
this should be able to go here. And yep, it is reflected. So if you remember, we used to
have some nested controls that didn't really make sense. I was doing that weird
meat/vegan thing. And now I just have
four checkboxes of some extra flavors,
my extra spinach, 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 they were also-- 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 was, again,
this form doesn't have associated
labels, so let's rerun and see if that fixes that. Yeah. And we're up to 98, right, and
we got rid of that weird form error here, right? Because it was saying, you
haven't given any context. You're making people navigate
through these weird nested controls and they're
selecting fillings, but 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
mat-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 a screen
reader, you're not getting stuck in a weird
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 with Material. And let's just keep trucking on. It looks like we're
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 these slider values. And if I go to my
Lighthouse score-- oops. Oh. If I go to my
Lighthouse score, this is exactly what this
is saying here, right? 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 this mat-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 mat-slider-- whoops. 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. So in my mat-slider, I'm
going to use aria-label and 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 codelab. 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 this description here
is "dumpling order quantity," its role is going to be a
slider-- it knows that already. And then the action is going
to be entering the slider. And all of that's going to be
handled by the voice screen reader. So we've added that,
and if I go back-- I've saved that, right? Yup. If I go back, I run,
I think it's going to say 100% 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're at the-- we've
already fixed everything that is automated, and this
is exactly where I say you can't automate all your checks. So this runs. Again, we ran our linter,
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-- oops. 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, and 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 has things like,
there's list key management, because that's
important, or FocusTrap-- 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 building an enterprise application
or you're maintaining an open source package or
something like that that has anything to
do with a UI, you should know about this page. So again, material Docs,
CDK, and the a11y 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. So 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. And actually, I
like alphabetical or semi-alphabetical, I guess. Somehow these things have
gotten slightly unalphabetical, but A comes first. So I'm going to import it. And now you're not
going to see anything, but if I go to my
NgTerminal, 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 Docs. 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 10, FocusTrap. I just talked about this, right? So I just said, hey, I notice
here there's this thing. Let's see. There's list key management,
there's LiveAnnouncer, there's focus monitoring,
and there's FocusTrap. But what's FocusTrap? Well, the CDK FocusTrap
or trap 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, hey, I want five bok
choy chili crunch tofu mushroom dumplings. I don't 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 a 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 navigating through
this and somehow, I'm 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 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. Right? You're not really in a place
to select fillings right now. You're selecting
your wrapper color. So let's go with this nice-- we're going hot pink. So now that we have our hot
pink five fun dumplings, let's look at how
to add FocusTrap. 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 cdkFocusInitial 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 trapped. Let's see, where is this? On step 10. But in our color picker
dialog, let's look at this. So in our color
picker dialog 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 cdkFocusInitial to ensure that we're focusing
on the selection list when we first open the dialog. So when we open
the dialog, we're not accidentally
focusing on, again, this home page or our shop,
because our focus really should be within this. If we think about our
other mat-selection-list-- oops. Let's think about our
other mat-selection-list-- this wouldn't make sense for
using that CDK directive, right, because here we
don't want to trap 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, [INAUDIBLE]
on the page, right? So we want to add
that directive. So if we go back, we've added
the cdkFocusInitial 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 trapping focus when
we have that behavior. Moving on, step 11, we're going
to do another CDK thing, which is using LiveAnnouncer. So LiveAnnouncer is
the idea that when a change is 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. Here, let me see if I can do it. Oop, did I do it? Mm. Well. Whoa. OK. Yep, VoiceOver does
not like my meat. Anyways, so obviously, you
can't hear my VoiceOver, 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. 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 any time 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 error. 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 10 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 LiveAnnouncer. 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 LiveAnnouncer to our color picker. So we're going to
go to our code. We're on TODO step, I
think we're on number 11. Oh, where are we? Yeah. Da-da-da. Yeah. OK. And in our component,
let's first make sure that we
notify the change. So first in our dialog
component in our constructor, we're going to change
our constructor to have a reference
to the LiveAnnouncer. So 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 LiveAnnouncer and some data. Oops. [INAUDIBLE] there you go. OK. Just wanted to make
sure I imported the things I needed to. Why is it mad at me? Oh. OK. There we go. Cool. So what I'm doing here is
I'm creating a constructor. I already had my
dialog reference, but now I'm just
injecting to make sure that I know what data is being
selected from that color dialog 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 LiveAnnouncer thing. So remember we imported
the module cdk/a11y? Now I'm importing my
LiveAnnouncer from my cdk/a11y 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 changeColor. Oops. Now I'm going to do
one other thing, which is before I close my
component, so before I use my dialogRef 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 change
my color, then I'm going to go to my
LiveAnnouncer object that I've already constructed
from LiveAnnouncer 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. So it's the
liveAnnouncer.announce. Super intuitive. If you're interested
in this, again, I can go to the
LiveAnnouncer docs. I can say, hey,
there's LiveAnnouncer, and I can go to my API reference
to make sure that I understand what is there. But look, my main
method is announce. And now if I were to go and
do that again, remember, any time 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 hot 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 I've used LiveAnnouncer. 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/a11y package, and
this is HighContrast mode. And so HighContrast
mode, I don't have Windows open right now, but
it's a Windows-specific feature called HighContrast 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 HighContrast mode,
very typically instead of 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 the 50s, the 60s. We want to make sure
everything is essentially 100%, right-- is 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. HighContrast 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 HighContrast
mode is super cool. Again, it's on Windows. And we have
something cool, which is the high contrast
mode detector in the cdk/a11y 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/a11y. You don't need
the tilde anymore, if you're following along here. But that is a recent
change to version 12. 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/a11y,
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 the
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
themes have that because I think that's important. And now let's go
to our application and see what that looks like. Oops. Ooh, why is it mad? OK. No. Hmm, I'm going to
try and rebuild. A fun thing where
rebuilding might save us. Or I will say, I
got through 12 steps before I ran into an issue. So I think that's
kind of impressive, all things considered. Yeah. Ooh, it does not
like that import. Do not know why it does
not like that import. Let's think about-- [HUMMING] OK. Well, I have something I can do. Remember how I said at the
end, you can git checkout main? Look, I have all my changes. Oop, and that's why. So it looks like we've
actually changed it. So you just import
the CDK, not cdk/a11y. So I should go and
change my codelab 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 codelab. Bonus points. So yeah, you can see that
in HighContrast mode, this would be applied, right? So cdk.high-contrast is how
we're going to reference this. And again, I actually think this
codelab is even more incorrect because cdk-high-contrast mode
is for version 12 and below and we've now changed the
reference to cdk.high-contrast, just if you're following
along specifically. And main should reflect version
13's version of these things. The codelab just is
version 12 and below, so I need to make
that code change. But I did get to the
very end of this codelab before I ran into
this, so I'm going to take that as a success. So since I'm not in
HighContrast mode, I just want to show
what that would look like by removing that media
query, just that you can see. And so that is a great example
of what HighContrast mode looks like. We're still like 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 can 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 like, this green could be
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 10 extra minutes, so I just want to
say congratulations. So if we think about it,
remember, we successfully-- oops, 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 a while 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
pats on the back for this. So yeah, so we got 100% there. Remember, we went linted with
our lint rules that we added. Oops. I'll run it again just
to prove how good we are. So we did linting. We used 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
selectable 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/a11y and some different
things including FocusTrap, live announcing,
and HighContrast mode in CSS. And so with that, you can count
how many different commits you have, but feel
free to again revisit this codelab if there
were specific steps that were tricky for you. Feel free to open issues
on the GitHub repository or tag me on Twitter @twerske. It's my last name, but
instead of the Y, an 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 wanted 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 Web Vitals to see where you're at now
and make little adjustments is a great place to start. Let's see. There was also a 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, because 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 DevTools?" There's some really
great resources if you prefer Chrome DevTools. If you even go to just
codelabs.developers.google.com, there's some great codelabs
there that are on DevTools. Yeah, let's see. Oops. Oh, OK. Well, 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 a super
broad question. If there's something
specific to accessibility that you want me to answer, feel
free to add that in the chat. "How is Angular's app
architecture different from other frameworks?" Angular is super
opinionated, but it's also-- it has a lot of
solutions out of the box. So Angular, if we look
at our application, each of my components, I have
a very familiar structure where I have HTML, CSS, or
Sass in this case, and then the component. And the component is where
I have all of my logic. The Sass is where I
have all of my styling. And then the 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 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, so we have the a11y 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
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, 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-- you were
only telling--" [INAUDIBLE].. OK, there's a question about
business logic resources for debugging, it looks like. So Chrome DevTools is mostly
for styling and visual changes, like all of these
panels really are about debugging visual things. If you're talking about
performance or things like that and you're developing
with Angular, I highly recommend you download
Angular DevTools, which does have things
like a profiler where I can record my change
detection cycles and then debug for performance. So-- ooh, let's stop that. I can see that somewhere back
there, 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 backslash
guide backslash DevTools. And DevTools 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. Oh, yep. 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're interested in any
of the specific recommendations I made, again, the codelab
is online and available at all times. [MUSIC PLAYING]