If You Follow This Checklist Your Sites Will Be 100% Accessible
Chapters16
The video highlights lesser-discussed accessibility practices beyond alt text and semantic HTML, presenting 17 key accessibility wins and a free cheat sheet to guide improvements.
Kyle from Web Dev Simplified shares 17 often-overlooked accessibility wins and practical fixes you can implement today.
Summary
Kyle’s Web Dev Simplified episode pushes beyond the usual alt text and semantic HTML focus to reveal accessibility wins many sites miss. He demonstrates concrete, real-world fixes—from properly pairing input error text with aria-describedby to using aria-live for dynamic updates, and from setting the autocomplete attribute to improve form UX to using inert to control tab order when drawers are open. He also covers how to make modals friendlier to keyboard users, why skip links at the top of pages matter, and how font choice can aid readers with dyslexia. Throughout, Kyle ties each tip to tangible code changes (such as applying aria-live with polite vs. assertive, or introducing the dialog element to handle focus and inert states automatically). He even walks through testing methods using Chrome DevTools’ rendering and Lighthouse accessibility reports to validate improvements. By the end, viewers get a practical 80-item accessibility cheat sheet in light and dark modes and a reminder that user-centric accessibility is about real-world use, not just ticking boxes.
Key Takeaways
- Use aria-describedby to connect inputs with their corresponding error messages so screen readers announce errors as users type.
- Apply aria-live with polite vs. assertive to announce dynamic updates (like toasts) without interrupting current screen reader activity.
- Add autocomplete attributes (e.g., given-name vs. name) to inputs to improve form autofill and password-manager support.
- Use the inert attribute to prevent off-screen or hidden content from receiving keyboard focus and screen-reader attention when dialogs or drawers are closed.
- Replace single-use, role-based UI hacks with native HTML elements (prefer button over div with role=button) to ensure proper keyboard interaction (space/enter) and accessibility.
- Ensure a skip-to-content link is the first focus target to speed access to main content for keyboard users.
- Consider dyslexia-friendly fonts (e.g., Atkinson Hyperlegible or Open Dyslexic) as an accessibility-friendly typography option alongside base fonts: smaller usability wins can improve reading comfort for a broad audience.
Who Is This For?
Essential viewing for frontend developers who care about real-world accessibility, especially those building interactive components, forms, and modals who want practical, immediately-implementable fixes.
Notable Quotes
"If you have error messages or other related text associated with an input you should use the aria-describedby attribute."
—Kyle explains how aria-describedby links error text to the input so screen readers can announce it.
"Use aria-live with polite or assertive to tell screen readers about changes, but polite for most cases so it doesn’t interrupt what the user is currently reading."
—This highlights dynamic updates like toasts and how to announce them without breaking the user’s focus.
"The inert attribute prevents you from interacting with content and hides it from screen readers when a modal or drawer is open."
—Kyle uses inert to fix tab order and focus management when overlays appear.
"The first link on a page should be a skip link so keyboard users can jump straight to the main content."
—Emphasizes the importance of skip navigation for efficient keyboard access.
"If you can just use a native button element instead of a div with role=button and tabIndex, you’ll get proper keyboard interaction by default."
—A caveat about using native HTML controls for better accessibility support.
Questions This Video Answers
- How do I connect an input field to its error message for screen readers using aria-describedby?
- What is aria-live and when should I use polite versus assertive in a live region?
- Why should I use the inert attribute with modals and drawers, and how does it affect tab order?
- What are the benefits of skip links and how do I implement them effectively?
- How can I test accessibility in Chrome DevTools using the rendering tab and Lighthouse?
Full Transcript
If you've ever researched accessibility, you're probably tired of hearing of alt text and semantic HTML because you already know all of that. So, in this video, I want to cover all of the accessibility stuff that nobody talks about and most websites get wrong. And if you want to have a full checklist you can go through with 80 different accessibility items ranked by category and by importance, I have a free cheat sheet in both light mode and dark mode you can download in the description below. In this video, I've highlighted 17 of these different items that I want to go through that I think are the most important accessibility wins that pretty much nobody out there talks about.
Welcome back to WebDev Simplified. My name is Kyle and my job is to simplify the web for you. And I have quite a few different examples that I want to go through for accessibility content. And the first one is going to be focusing specifically on forms. So this basic form right here, if we start typing some text into it, you can see that we get a warning error that says that the name must start with KY. Otherwise, it's going to give us a warning. So, this is a basic form and everything works like we expect it to.
The problem is that it's not very accessible. Sure, we have the basic accessibility wins of, for example, putting a four attribute and an ID on our element, but we don't have anything else. This error, for example, is not at all accessible because when we type something in incorrectly, as a user, I can visually see that this error appeared on my screen, but if I'm someone that's using a screen reader, I have no way to know that this error is here. Also, I have no way to associate with this input or anything like that. So one thing that you should always do when you have error messages or other related text associated with an input is you should use the area described by.
What this does is it takes an ID of an element that describes additional context for this element. So in our case it's giving us the error message for our input. So we can just give it anything we want. We're going to give it an a name of name error. That'll be our ID. And then we just specify the ID in our case name error on the element we want to associate it with. And now essentially for screen readers, this text that's inside this error element, which is where this text goes whenever we have an error, will be associated with this input.
So as I'm typing in my text content, and I can see that this error is here, that'll show up for the user when they select this input element. Now, this still isn't perfect though because the text currently starts out as blank and it gets added later. Whenever you have content that is being changed on the screen, you need to use what is called the area live attribute. And this will essentially tell screen readers that content inside this thing is changing. And you want to set it to a value of either polite or you want to set it to assertive.
In 99% of times you want to set it to polite. If you set it to assertive, essentially what that'll do is every time the content inside this section changes, for example, our error is added to this section. It will immediately interrupt the screen reader and tell the person whatever that text is, no matter what they're doing, even if they're reading something entirely separate. By using polite instead of assert, it'll let them know about this error or new text as soon as there's nothing else that's currently being read. So, if they're in the middle of reading something, it'll wait till the end of that and then let them know.
Just doing this already adds a ton of accessibility because now we have our error being described in our input. So, once someone's in the input, they know what it is. And if they are typing and the input error appears, they will get a warning for that particular thing telling them that the error has appeared. But not all accessibility things need to be focused on people that have issues with vision. Instead, I want to add accessibility that works for everyone. one as well. In our case, the autocomplete property should be put on every input that it's applicable for.
So, in our case, you can type autocomplete. And as you can see, there are about a million different options you can autocomplete. And in our case, this is someone's first name. So, we can use the given name property, and that essentially specifies that this represents someone's first name. Now, I'm going to get autocomplete in my browser for things like password managers or other autocomplete type stuff. You'll now see that when I click inside here, I actually get drop downs that specifically prefill this information with just my first name. Now, if I were to use name instead of given name, that essentially says I want my full name.
And when I click, it'll now fill out my full name information. So, I'm getting that full autocomplete. Now, I'm using one password for this autocomplete, but there's tons of different things that'll autocomplete for you. And especially if you're like on a phone or something, this is really handy to have because a lot of people have this type of autocomplete behavior, but you will never get it by default. you need to specify this autocomplete property given the property that you want. In our case, name, given name, or something else. Now, I want to dive a little bit further into that area live attribute because it can actually do a lot more than just what I showed.
In our case, we have this toast notification. When I click this button, a toast message pops up right here. And already this code is using area live. If we look inside of our code, you can see we have area live set to polite. So, every single time that a new text gets or a new toast message gets added into this section right here, it's going to notify the user in a polite way to let them know about this notification. But you'll also notice two other attributes. We have area relevant and we have area atomic. These are two attributes that can modify how that live attribute works for the area.
So, Arya atomic essentially you can set to false or true. And if we look at the values here, false is the default. So, the fact they even have it listed is not required. False just presents only the things that have been changed. So, in the case of this example, every time I add a new toast, it'll only read what the newest toast message is. It won't reread all of them. But if I wanted it to reread all of them, I could set this to true, and it's essentially going to reread everything that is inside of my live container anytime any part of it changes.
And if I want to modify what changes are actually being used, I could use Arya relevant. And for this one, you have three specific values. You have additions, you have removals, or you have text. Or you can put in all, and that's essentially a shorthand for all three of these different kinds. So, additions are whenever a new element is being added and text is whenever the text content is either changed or added inside of this section. By default, additions and text, which is what is listed right here, is what you will get out of the box if you don't specify this.
But you can also use removal. So, anytime that text or elements are removed from the page, it'll also notify the user saying that that thing was removed from the page. For the most part, that's not as important for things like toast messages or error messages, but it could be really useful for certain situations. By default, the Arya relevant is going to be additions and text and the Arya atomic is going to be false. But again, you can modify those however you want. For example, if you want to have a list of error messages that you notify anytime it gets updated.
You could use Arya atomic of true and the Arya relevant, you could add removals into there. That way, it doesn't matter if you're adding or removing errors. It'll let the user know as soon as either of those different changes happen in your application. And this entire section is built using the toast message inside of Shadan, that sonner component. So you can see already by default they have accessibility built into those components. Also something that's a huge bonus here that wasn't even something I was going to talk about is you'll notice that this section right here which is the thing that is the Arya live it has a label of notifications alt t and essentially what that lets the user know is that when these notifications happens it essentially says hey this section is for notifications and if you click alt plus t it'll essentially put your focus inside of that section.
So when I click alt t and I click tab you can now see I can tab between these different elements. that red background is just the element I'm currently tabbed on. So, by using that alt t shortcut, I can immediately jump to where that brand new notification was. So, this is really nice because as a screen reader, I have to hit tab a lot sometimes to get to these different toast messages and so on. But with a keyboard shortcut, it lets me jump directly to that location, which is really handy. Now, this next issue is a huge pet peeve of mine and something that so many sites get wrong, and that is that they have their tab order all messed up and not in the ways that you may be thinking.
Let's take this simple site for example. You can see when I'm tabing through right here, I'm on these other buttons, which makes a lot of sense. And if I start all the way at the start of my site, you can see the first thing I hit is this giant menu button, which is fine. When I click tab again, you think it would go down to this other button right here. But when I click it, you notice my tab seems to completely disappear. Now, if I click shift and tab, that brings me backwards. And you'll notice it brings me back to the correct location.
And if I click tab enough times, eventually it'll make me to that other button. So, where is my tab at between all these different times? Cuz I have to hit it a bunch of times to be able to get between these different things. Well, if we look at our actual code over here, you can see we have our site. The first thing that shows up is that button that we tab onto. That makes sense. Then we have this overlay. Then we have this aside element, which is like our drawer that's happening. And this is rendering on our screen even though it's off the screen.
You see how it slides in and then slides off, but it's still being rendered, which means that what's happening is it's tabbing through every element on this thing that we can't even see on our page. Then after it gets through all that, it finally moves through and starts tabbing through all these buttons down here. So, this is our problem. When we have content that is off the screen or not visible, we want to make sure it's impossible to tab onto that content. Now, this is really easy for us to do. All we need to do is just add the inert property directly onto there.
The inert property essentially prevents you from interacting with this content in any way and it completely hides it from screen readers. That one fix solves all of our problems. For example, if we're on this other button and we click shift tab, we go back up to here. When I click tab, I move down to the next one. I've immediately completely removed this drawer sidebar thing from my tab indexing. Now, when I have this open, I obviously want to be able to tab through it because right now I can't interact with it or do anything. It pretends like it doesn't exist.
So, inside my JavaScript, what I want to do is where I have my drawer here, when I open it, I want to set that inert property to false. And I want to do the exact opposite and set it to true whenever I close it. So now when I open this up, I can tab around inside this content just fine. And when I close it, we'll know that my tab lets me skip right over that content because it essentially that inert keyword makes it pretend like it doesn't exist at all. Now, we do still have a problem though with this site.
And that is let's say that I'm inside here and I'm tabing around and everything's working great. But the problem is if I just make my screen a little bit wider and a little bit less zoomed in, we'll be able to see this. If you take a look at these buttons right here when I'm tabbing through, you'll notice that I'm actually able to tab and interact with content that's behind the thing that's supposed to be covering my screen. This is really common with things like modals or pop-ups or drawers like this. I want to make sure I can't interact with the content behind here.
But right now, I can clearly interact with all these buttons using the tab keyboard. So again, that inner property is going to be what saves us. So what we can do is we can just wrap all the content that we want to hide. In our case, everything except for our aside here. So we can just take our aside and overlay and move that outside of this container. This we just called site. So this site container contains literally everything. And then this is just the content that's outside of our site. And now in our JavaScript, we have that site variable right here.
We can set the inert on this one to true. And down here, we can set it to false when we close our modal. So essentially, we're flip-flopping which things are inert. While my sidebar is open, the section right over here, if I just expand this further, the section in here is not inert. And I'm able to tab through all this just fine. But when it's closed, that section is inert. And I can only tab through the content inside my section. So this is a great way for me to flip-flop between these two to work with them.
Another thing you could do is use the dialogue element in HTML. I have a full video covering it. I'll link it in the cards in description, but that automatically handles all the inert stuff for you, so you don't have to manually do it yourself. Now, if you're enjoying this content, I highly recommend you check out the full check sheet in both dark and light mode. Like I said, it's got over 80 different things on it, and you can just go through it as a checklist anytime that you're adding features or testing out your site. Now, the next thing I want to talk about is actually still on this page.
We'll zoom it in so it's a little bit easier to see, but if we open up this model, first of all, you'll notice that this button right here for our X is incredibly small. When I actually tab onto it, you can see how small this is. It looks large because I'm very zoomed in. But if I actually zoomed out to 100% zoom, you can see at this zoom level, this button is very, very small. It's actually 20 pixels wide. If we took a look at the CSS, we'll just expand this out a little bit. And you can see right here, close button size of 20 pixels.
This is obviously not good. The recommended minimum size for any interactable element is 24x 24 pixels. So, this already falls under that size. And they even recommend going up to 44x 44 pixels if you really want to make sure that it's super accessible for touch screens because I don't know about you, but if you've ever been on a website where they have really tiny buttons and you're trying to push them on your phone, it's really easy to accidentally click the wrong button. So with this, we should just bump the size of our check or our X mark up.
And now you can see it's a much chunkier, bigger box. Much easier for us to click. And even at 100% zoom, it's not too terribly large. Another thing that's actually a huge problem with this button is it doesn't even work like we expect it to. If I tab onto this button, everything seems like it's fine. But if I click the space bar or enter to try to press on this button, nothing actually happens. When I click it, it closes just fine. But it does not work when I'm tabbed onto it. And that's because of the way that we actually wrote out this button.
This is something that I see all the time inside of websites is people will use divs or spans to work as elements and they think that they're fine because they put a roll of button on here or something like that and they throw their tab index on there and they're like, well, it looks like it works. You know, I can clearly tab onto this element, so everything should be fine. But if you're using something like a roll button or tab index to override how something works to make it work like something else, you need to hook up all the JavaScript and everything behind the scenes.
And nine times out of 10, if you're using these complicated Arya attributes and rolls, you probably just want to use a normal button element or something else instead. So in our case, we should just be using a normal button, not messing with any Arya related roles or anything like that. And now our behavior is going to work just fine when I use spacebar to actually click on that button and close that modal. So, one thing to watch out for if you're kind of obsessed with accessibility is you may go overboard on Arya attributes and roles and custom elements, but nine times out of 10, if you can just use a plain HTML element, that's going to be the much better approach for you.
Only use those complicated roles and Arya attributes for specific situations where c or where normal elements like the button don't actually work. Now, I want to rapid fire through these next couple. The first one is that if you're on a site, the very first link that you should ever get to when clicking tab should be a skip link. You can see when I click tab on this page, the first thing that pops up is this skip to main content link. And when I actually click on this link and interact with it, you can see it brings me down to the very main content of the page.
And it skips over all this extra stuff. Because if you can see, I click tab a bunch of times. I have to click tab so many times before I finally get all the way down to the main content of the page, which is obviously not a deal if you're using a screen reader. So, you should always at the very top of your page have a skip to main content link. I actually have a full video covering how to do this in CSS. So, I'm going to link that in the cards and description for you if you want to go more in depth.
The other thing that's super important in your application is you should have either the option for an alternative font or you should have a font that is friendly to either people with dyslexia or difficulty reading. Now, this could take the form of like a full-on dyslexic font like open dyslexic is a font that's specifically designed around being easy to read for people with dyslexia. And you could have that as like an alternate font people can swap to just like they could swap between light and dark theme. Or you could go a more middle ground approach and use a font that's specifically built around legibility.
So this Atkinson's hyperledible font or Lex are both fonts designed specifically about being as legible and easy to read as possible. So having fonts that lean a little bit more towards easy to read is super important. Even if you just have one base font, as long as it's got an easier to read font, that can really help people especially if they have dyslexia. Now, this next one is something that so many developers get wrong, including myself when I was first getting started. I've taken a very heavily modified version of this project, which is from my CSS simplified course.
If you're interested, I'll link it in the description for you so you can check out the full course where you build projects like this and many others. But essentially, what I have here is a simple system that you've seen on a lot of sites. We have some text and we have an image. We then have the flipped version, image, then text, and then again, we have text and image. Super simple. And you can see if I tab through this content, it works fine. Everything that I tab to is highlighted in this giant red. So you can see this read more button.
Then we move over to do something, move back to do something, read more, read more, do something. Super straightforward. It's left to right, top to bottom, just like you would normally expect in a website. The problem is though that the mobile view of our website does not actually work like you expect. Let's shrink this down to mobile. And now you'll notice that we just stack everything. It goes text, image, text, image, text, image, just like you would expect in a mobile version of this exact same site. So, if we try to tab through this content, you can see first read more.
That's great. Then it goes to this do something. And you'd think it would go to this read more button next, but instead it skips that and goes down to this button here. And then it jumps back up to the read more button. And then it finally jumps down to read more and the do something button again. So you can see we're skipping where we should be at. And this is specifically because we're rearranging the order of our HTML elements inside of CSS, but we're not reordering them in our HTML. If we take a look at our actual code for this section, you can see we have three section elements.
one section, two section, three section. Those represent, if we expand this out a little ways, these three sections of content and one of them is labeled as section reversed order. Now, if we look at the code inside this section, I'll just minimize down so we can see the important part. You'll notice first we have our image and then we have our text, which is the exact order we have our content inside of here. That makes sense. But on a smaller screen size, you can see that I'm changing the order of this. I'm using flex direction column reverse.
All that does is it flips the order of how these things render, but it doesn't change the order of your HTML. And the only thing that your tabbing keyboard cares about is the order of the HTML. So, we rearranged the order visually, but we didn't change the order in HTML. This is something that can be a massive problem because now things that are laid out in a specific visual order change completely in the actual order that they are in the HTML. Realistically, what I should be doing in this example is I should have this section completely flipped where the image is second and my text is first.
So, it's just like all my other pieces of content where the text comes before the image. But then on large screen sizes, I flip the order of them. So, this should essentially be reversed to a min width just like that. And we can specify that this should be row reversed just like that. And now you can see we get the exact same layout that we did before. But when we tab through this, the order is a little bit more logical. You can see it goes read more, then it goes button, then it goes read more, then button, then read more, then button.
So, it has the exact same flow that it did before. And on a small screen size, we still get the same exact order. You get read more, button, read more, button, read more, button. So, it's important to think about not only the actual structure of your HTML, but also how that content is visually showed on your page. Because if those things are too different from each other, it could really change how your tab ordering goes. Now, I want to move into a final section that's all about testing. The very first thing you should test is just try to use your website without your mouse at all.
Just go to your website, see if you can do everything using just keyboard shortcuts, and that's it. If you can't, then obviously your site is not accessible because you can't use it with just a keyboard. The next thing I want to talk about is features in the dev tools you can use to make testing for certain things easy. If you go to the rendering tab in your CSS Chrome dev tools, just type in control shiftp and then you can type in rendering. That's going to bring you to this exact rendering tab. Scroll down a little ways till you get to this section about emulation.
And now you can emulate essentially all the different accessibility features you would ever want. For example, you can do color scheme, which is great. You can also have forced colors in here, but most importantly, you have these things down here. Prefers contrast. So you can test what your site looks like with prefers contrast, prefers reduced motion, prefers reduced transparency. You can test all those different things. And you can even go so far as to emulate different vision deficiencies. This is the section I really love. You can, for example, test what your site looks like for people that have blurry vision, maybe not super sharp vision.
You can test what your site looks like when you reduce the contrast of things or for example for various different colorblind modes or even full grayscare. This can give you a really good idea of how your site is actually working at various different levels of color blindness or various different levels of disability when it comes to seeing. And as long as your site is still functional when it's for example not able to have any color or blurry, you know that at least your site is overall quite functional. You can even force the scaling of the font size.
For example, I can set this to 200 to emulate a larger font size, and my site should hopefully scale properly to this 200% increase in font size. Looks like mine's not for some reason. So, there may be something wrong in my CSS that I would need to fix to make this actually properly work. Another really great tool that you can use is you can go over to the Lighthouse tab and in here you can actually test various different things. Specifically, there's an section for accessibility. So, if you only care about accessibility, you can just come in here, click the analyze page button.
It's going to do a bunch of work to analyze your page behind the scenes, but it'll give you an overall accessibility report that helps you with a lot of the more basic things. We got 100% on this one, but it'll tell you if there's any accessibility problems. Also, color contrast is a really easy thing for you to be able to test. For example, all I need to do inside of my application, anywhere that I have color, if we just make this a little bit larger, I can click on that color and if I find one that has got text behind it, here we go.
We'll inspect this one right here. We can click on this. And now you can see I'm going to be getting a contrast color. I'll just pick the background color here. And you can see it gives me a good contrast ratio. AAA is the best standard to have. Double A is also pretty good. But you can see as I move this around, you can see that my contrast levels change. This is a great way for me to check my contrast. Most of the time, this contrast picker is automatic. So, for example, if I look at the color of this button text here, we'll just check this one.
And the reason it's not showing up automatic is because I'm using a variable. But if I were just say like color black. There we go. And now I look at this one. Since it's a hard-coded variable, it knows where it's at. You can see I can get the exact contrast ratio for where this text is with the background color that it's associated with. Now, if you want to make sure you master all the tips in this video, plus all the other ones in this checklist, I have over 80 in this checklist. I'm going to link it down in the description.
I highly recommend that you download those. Again, it's in light and dark mode. Also, I have tons of other accessibility videos. I'll link some of my best ones right over here so you can really deep dive into mastering accessibility. With that said, thank you very much for watching and have a good
More from Web Dev Simplified
Get daily recaps from
Web Dev Simplified
AI-powered summaries delivered to your inbox. Save hours every week while staying fully informed.









