Forms are the single most important element for user interaction in a web application. Without forms, a user can neither enter a search term on Google nor post comments on Facebook. So why is it that in many applications forms are so badly designed that they are barely usable by the common user and not usable at all for users that depend on tools like a screen reader? This article describes why accessible web forms are a benefit for every user and shows 5 easy steps to make a web form accessible. Impatient? Go straight to the slides or the github repository with the examples.

Why Accessible Forms?

When the term “accessiblity” is used in the context of a web application it usually conveys the meaning that users with some kind of disability like blindness are able to use the application. For me, the term “accessibilty” also includes the common users of an application. An application in general and a form in particular can be inaccessible even for a user who can see and use a mouse if it is badly designed. Take this form from badforms.com, for example (yes, there is a website dedicated to exposing badly designed forms!). The values of the input fields are also used as their labels. If you tab into the field, the label simply disappears and you have bad luck if you forgot what the label was. Is this form accessible? Certainly not. It’s not even accessible for a user without disability! In more conventional terms: the form has bad usablity.

Since forms are a very important part of every web application, they should have good usability. Otherwise, the users will complain and the application’s acceptance will suffer. It’s not hard to make a form usable for all users, disability or not. The 5 easy steps described below go a long way towards making a form usable and accessible for everyone.

Step 0: The Example Form

The example used in this article is a money transfer form inspired by the online banking web application of my bank. It doesn’t have a pretty CSS design, but that’s not the point of this article. The form has some flaws from a usability and accessibility point of view which will be addressed in the following steps.

Step 1: Add <fieldset>s

The HTML <fieldset> element is an easy way to give structure to your form. Its only purpose is to provide a grouping mechanism for a set of input fields that belong together. A fieldset in HTML looks like this:

<fieldset> <legend>Recipient</legend> <!-- put all input fields concerning the recipient of the money transfer here... --> </fieldset>

So what’s the benefit of having fieldsets? By default, you get a visual clue that some input fields belong together – giving structure to your form (you can make the fieldset invisible using CSS, though). What’s more, a screen reader reading the form to a user will now always read the <legend> of the surrounding <fieldset> to the user when he tabs into a input field. Instead of labelling the first input field in the example “Recipient (Name or Company)” you can now simply label it “Name or Company”, since it is clear that it belongs to the recipient. It just looks (and in case of a screen reader: sounds) clearer this way.

Step 2: Add <label>s

HTML provides the <label> element for defining labels for other HTML elements. This is insanely easy to do…all the more astonishing that it’s not used in important web applications (like my online banking):

<label for="recipientName">Name or company*</label> <input id="recipientName" type="text" name="recipientName" />

Every input field should have a label of some kind. Otherwise, how is a user supposed to know what to enter in that input field? The <label> element simply adds some semantics to the label that makes it possible for tools like screen readers to find the label for an input field and read it to the user. Screen readers are intelligent enough though, that when they don’t find a <label> they will simply read the text in front of the input field. However, using <label>s gives you the flexibility of not having to put the label right in front of the input field.

You may notice that in the example form I also added <label>s to the “transfer reason” input fields which didn’t have any kind of label before.

Step 3: Add Field Hints

Some input fields require more information than just a label to help the user fill it out correctly. A good example for this are input fields in which the user is supposed to enter only digits. How is the user to know he is to enter digits if it doesn’t say so? Most users know from the context that a bank code consists of digits…some users don’t know this (for example when they are confronted with money transfer for the first time). Knowing they are supposed to enter only digits helps them to enter the correct information. Hints can be added to an input field like this:

<input id="recipientBankCode" type="text" name="recipientBankCode" aria-describedby="bankCodeHint" /> <span id="bankCodeHint">Please enter digits only.</span>

Just add some text right behind the input field to tell the user what is expected. To support screen readers, add the attribute “aria-describedby”. This tells them where to find the hint for a certain input field so they can read it to the user when he tabs into the input field.

The WAI-ARIA standard provides many more attributes like “aria-describedby” that add certain semantics helping screen readers to decide what to read to the user. However, simply using “aria-describedby” for an input field already goes a long way towards accessibility.

Step 4: Add “Required” Semantics

For some input fields the user is required to provide input, for others he is not. It’s an unwritten law to mark required input fields with an asterisk (*). It’s actually fine to do this – assuming it is documented in a prominent spot that your form uses this convention. Otherwise, users that don’t know what the asterisk means are lost. However, there’s a more elegant way to mark an input field as required:

<input type="text" name="recipientName" required="true" aria-required="true" />

The “required” and “aria-required” attributes actually do the same thing: they make screen readers read to the user that this field is required. What’s more, most modern browsers will also know that the given field is required and will show a message like “this field is required” if the user tries to submit the form without entering a value. It doesn’t hurt to use both attributes – this way even software that only knows one of the attributes will be able to tell the user that the field is required.

Step 5: Add Even More Semantics

With HTML5 came a bunch of new attributes with which you can add certain semantics to your input fields. Where there were only input fields of type “text” before, you can now add input fields of several types like number, date and email. We can now change the HTML of our “amount field” to the following, for example:

<input id="amount" type="number" min="0" step="0.01" name="amount" aria-describedby="amountHint" required="true" aria-required="true" /> <span id="amountHint">Amount in Euro.</span>

Note that the “type” of the input field has changed to “number” and we also added a minimum value and a step size that tell the browser and screen reader that you cannot enter a negative value and that the smalles amount size is one cent. If the browser supports the number type, the browser will show an error message on submit if the user enters characters that are not digits or decimal delimiters. Sadly, the screen reader I tested with (JAWS) did not read the “min” and “step” attributes to me. It still read “Transfer Details. Amount. Amount in Euro”, so actually nothing changed here from Step 4. However, we added more semantics that can hopefully be evaluated from future generations of screen readers.

Caveat: Limited Accessibility of Automatic Browser Validations

With steps 4 and 5 we added semantics to some input fields that cause modern browsers to display error messages when the form is submitted and the user has entered something that does not abide by those semantics (i.e. he entered characters when he was supposed to enter digits). This is a very nice feature for visual users. However, my tests with the JAWS screen reader and Chrome showed that these error messages are not read to a user relying on audio. Thus, when he submits the form, he gets no feedback whatsoever and may even think that the form was submitted successfully. Obviously, the browser and/or screen reader developers need to fix this. Perhaps this is only true for Chrome. However, I will look further into this and try to find a solution if the problem also occurs with other browsers.

Conclusion

The above 5 steps showed how to increase the usability and accessibility of an HTML form by minimally enriching the HTML markup. This is hardly a lot of work and will even fit in the tightest project schedule. As it is with everything in software projects (and projects in general): if you take care of the usability and accessibility of your forms right from the start it’s a lot cheaper than adding it at a later point in time.

Steps 4 and 5 should be used with the caveat in mind that they may result in automatic input validations by the browser which are not picked up by screen readers (at least not in the combination of JAWS and Chrome that I tested with). However, instead of abandoning semantics altogether, there must be a solution using javascript (coming up shortly).

Slides

I recently held a talk about this topic. Feel free to have a look at the slides. They’re available at slideshare.

Resources