Accessible Forms with ARIA Attributes
00:00 Let's pull up our editor and come over to our error list. So we're going to need to have an ID on this UL, so that we can associate this list of errors with the inputs that it's making an error about or even the form. So let's take an ID attribute,
00:19 and that will be an ID of optional type string. Then here we'll say ID is the ID that we've been given, and that takes care of that. So then we can come down here, and now the trick with ARIA attributes is, we need to make sure that they are not even present if they shouldn't be there.
00:38 So if there's no error, we don't want to have an ARIA described by, and if there's no error, we don't want to have an ARIA invalid at all. So an ARIA invalid of true or false is not the same as not having the ARIA invalid at all. It's annoying, but that's the way that it is. Then we also don't want to have an ARIA described by
00:57 pointing to an element that doesn't exist either. That messes with some screen readers as well. So we are going to do some calculations up front with all of these. I'm going to say const and then equals, and we'll just do this right here. So the form has errors.
01:15 That is going to be just a Boolean of whether the, here, I think we'll get better copilot complete if we just do it this way. Here we go. So yes, if there is any length on the form errors, then we have form errors. Then if that is the case, then we'll say form has errors.
01:33 If it is, then we'll say form error. This can be whatever we like or undefined. So if we pass undefined as our prop for our ARIA described by, then that prop won't show up. So we'll finish the rest of these, but let's start with these first. This, I think, will make it more clear for you.
01:52 So ARIA invalid will be form has errors or undefined. Then an ARIA described by, this is going to be our form error ID. In our case, we fall back to undefined, so we can just say that. There we go. Awesome. Then we're going to
02:11 do the exact same thing for the rest of them, but let's not forget, we need to pass that form error ID to our error list, which is right here. So let's say ID is that form error ID, solid. All right. So let's do the same thing to the rest of these, and Copilot could probably help us with the rest of these if it thought about it for a second.
02:30 Come on, Boolean. Yeah, there we go. And then we have our title has errors, and if it does, then we have our title error, otherwise undefined. That works out perfectly. And then here we have our Boolean on the length of errors on the content, and our content has errors, content error. Perfect.
02:50 Then we come down here, apply the ARIA invalid, invalid, and the ARIA described by, and then we provide the ID for our errors on the title error ID. And then we're going to do the same thing for our content text area.
03:10 And right here also, content error ID. There we go. Awesome. And with that, now we can take a look at our accessibility tab. Here, let's submit it so we get that error. We get the styling now, so that's nice because it was based on ARIA invalid.
03:27 There is a pseudo selector in CSS for if a field is invalid, but using ARIA invalid instead means that any custom validation logic that you add to it will also trigger this. It is generally a good idea to communicate the validity state to the input,
03:45 but typically you're going to use libraries for that. And using ARIA invalid is pretty much required anyway. So I just use ARIA invalid, and that way, if I don't get the outline, I'm like, oh yeah, I need to include the ARIA invalid for that too. So you can use the pseudo selector, but I prefer to use ARIA invalid instead. And that's why we have the styling the way we do.
04:04 Okay, so we have ARIA described by title error. We look at that, and that has the proper ID. We turn on our voiceover, our screen reader on Mac, and we get title required and validate edit text, and then more content available. We press the hotkey it's telling us about,
04:22 then we get the more content is title is required. So that is exactly what we were trying to do, and we did it, so good job. You should feel proud of yourself. You made your app much better for users using assistive technologies, and everybody else, it's awesome.
04:37 So in quick review, you basically just need to provide an ID to where you're displaying the errors. We display our errors as a list because you can have more than one error, and I think that's the proper, the best way to do it, the best way I have found to do it. But we wanna give an ID to that element,
04:55 and then you determine whether or not the thing has errors and place an ARIA invalid and an ARIA described by if that has errors. You'll notice on the content here, this does not have an ARIA invalid or ARIA described by. This is correct.
05:12 You should not have those attributes if things are not invalid. So there you go. Oh, I should also mention, ARIA error message is also a thing, but due to lack of consistent screen reader support, it is not recommended. So that's why we use ARIA described by,
05:31 even though it's a little less semantic feeling. It is more correct due to the varying levels of screen reader support. Maybe one day in the future, we'll be able to use ARIA error message, but yeah, screen readers are tricky. So that's how you associate your error messages with your fields.