Doing forms correctly
Forms are incredibly complicated to get right from an accessibility standpoint. I don't know all the good practices but I've seen some bad ones that I can warn you about. Please contact me if you find a mistake in this section as I really am not 100% sure about everything.
Forms require strict HTML
- A form starts and ends with the
<input>, no matter its type, needs and
forattribute pointing to it.
- If you have a multi-section form, regroup them with the
<fieldset>element and add the
<legend>element as the "title" of this fieldset.
- End your form with a
<button>when you can, use the
forattribute to point on the form's id, and use an
aria-labelto give more context.
For accessibility reasons:
- Use contextualized text for your labels, be precise about what each input is about! If you can't have a clear label, same as links: add a
titleattribute to the input as well as a
- Don't rely on the
placeholderattribute for examples of what is expected! The placeholder text is often hard to read and disappears once the input becomes active, making it difficult for users with cognitive impairment.
- If you want to add an example of what is expected from the user, you can either add it directly in the label (often not very accepted by designers) or add it below the input and then refer to it with the
aria-describedbyattribute (see example below). Using this, screen readers will first read the label, then the
aria-describedbytext in one go.
Wrapping it up, here's an example that you can inspect with your browser's developer tools:This is a form demo below, not a real one, don't activate it!
That's it for the code, but more often than you think, bad forms are the result of non inclusive design practices, some of which we will see below.
Information below forms
Ever filled a form and right under the validate button, seen a wall of text written in 10 pixels size that is actually the terms and conditions? Well that can be a problem!
Most forms end with words like Continue or Validate and by doing so, suggest that the page is finished. A screen reader user can't know there's something else below.
This problem can be super tedious to explain to designers as most of them don't want a wall of text before the form, and don't ever suggest this to a marketing team! So an accessible solution is to simply use an invisible anchor link pointing to the wall of text right before the form starts.
Screen readers users are humans too, they dislike walls of text about legal stuff like anyone else! This solution allows them to either read it or even better, skip it, like we all do right?
Don't put text sections inside a form!
You probably already tried to tab between inputs in a form. That's because inputs are capturing elements that you can only escape by using the tab key. And when you do, the tab key will lead you to the next native focus-able element like another input, a button or a link.
It's important because too many designers put big explanation texts about the form between inputs. Since screen readers users can only use the tab key to get out of an input and will land on the next focus-able element, they will not have the explanation texts vocalized and have no way of access them. We saw that
aria-describedby can be used to link to a descriptive text, but that's applying a bandage on a broken leg.
Removing texts sections inside forms might seem like a chore and, when talking about it with designers, they will probably tell you it's a going to make the whole experience bland or suffocating in the case of massive forms.
But the reality is that a form that needs explanation texts between inputs is a bad design right from the start. You should give all necessary information before filling the form, otherwise users might start filling it and realize in the middle they didn't have to, or are not concerned about it.
Your labels with the descriptions attached should be enough to make it a pleasant and understandable experience. Yes forms are not fun but we can't sacrifice usability to some funnel concept marketers enjoy to create.
Handling errors in forms is a pain
Handling errors in forms is super complicated and nobody seems to agree about how to do it correctly. It's especially hard with accessibility in mind, and not only because of screen readers. So take my advises with a grain of salt as I may be wrong on some cases and am still learning about this.
The first rule to respect is that triggering error messages should only happen either when the user tabs out of the input or when the user validates the form. Don't trigger error messages while the user is typing. Wait for him to go out of the input or it will be a vocalized nightmare or a panic inducing behavior. You might think that's counter-intuitive as screen readers users may not know that they wrote it wrong but that's actually OK if you do the following right.
When the user validates the form using the button, if an input is required and not filled or wrongly filled, move the user focus to this problematic input using the
The error message should be added the same way as the instructions, with an
aria-describedby. You can actually have two
id as a value for
aria-describedby, so screen readers will read the label, then the description, then the error message. Finally, a
aria-invalid="true" needs to be added to each invalid input.
error id to each input's
aria-describedby so screen readers can vocalize the error message, and remove the
display:none from the error message itself so non-screen readers users can see it too.
Because of all this and contrary to popular practices, it's forbidden to disable a form button, even if the user made errors or did not finish filling the form. If the validation button is disabled it disappears from vocalization and the user has to travel through the whole form to find which input is not good. This is less practical than sending him directly to the input when the button is clicked.
Applying this can be tricky on legacy applications that handle errors in a monolithic way. Even if you do front-end surface level error checking, the user might make a typo that can only be identified when the form is sent and the back-end discovers it by using information stored in a database. If this happens, the error handling in the back-end needs to be written in a way that returns which information is wrong, to allow the front-end to
.focus() on the wrong input.
If the back-end returns a vague message then the front-end can't do anything outside using
.focus() to move the user to a standard error message, and the user has to redo the entire form and find by himself what he did wrongly. This is a super bad user experience even for non-disabled users.
The best solution is of course to do error checking on the back-end on each input with an ajax call right after the user exits it. But for various reasons going from time to cost of requests, it's not always possible.
Good luck with your forms and more than anything, test your forms with real users, disabled or not, to find out if everything is ok. On this particular subject, you can't trust yourself, your client, product owner, designer or common tester. You need real, fresh experience.
Next: Tables are not that complicated