5 Steps Towards an Accessible Web Form

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:

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

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:

     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.


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).


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




  1. xnor

    Thanks you for this comprehensive overview. Quick note: the link for “This stage of the form in the browser” in example 5 points to example 4.

  2. bzk

    I think that the form could still be improved in many ways.

    For example the one cent/penny increment of the transferred sum is really not very usable. I expected a step of 5 or 10 euros/dollars. You can also skip a reason line and not get a validation error. Why are there 4 reason lines anyway? Why not a textbox?

    I can enter a date that is in the past and not get a validation error.

    The layout has too much space between the labels and the input fields. Right aligned label text would take care of this problem. See Bootstrap’s forms for a good example (some random screenshot: http://bit.ly/1928Apm). Using a UI framework like Bootstrap is also useful since it enforces fieldsets and other visual clues, and valid markup.

    • Tom

      I agree fully that the form can be made more usable and more accessible! This article just covers the basics which should be generic enough to be applied to any form in any domain. There are many more things that can be done that are domain specific like explaining why there are 4 reason lines or not allowing a date in the past. The 4 reason lines are actually just copied from my online banking form (don’t ask me what they are for…but yes, a good form should explain that). And dates in the past should actually not be allowed…I will fix that.

      Of course a form in a real application should have a neat and clear visual design. Since I’m a programmer with bad design skills, I skipped this part. However, I will indeed have a look at Bootstrap and perhaps make the examples a little more eye pleasing…thanks for the hint!

      As for the step attribute: I interpreted the meaning of this attribute to be the minimum possible step between two valid values (see http://www.w3schools.com/tags/att_input_step.asp). Hence, for a currency field in EUROs it should be 0.01 EURO = 1 Cent. However, seeing what you expected makes me think that this attribute is not so good for usability/accessibility after all since many users will wonder why the browser displays buttons to add/subtract 1 Cent to the current value instead of bigger values. I believe the step attribute should be used by a screen reader to read it to the user and by a browser for client-side validation instead of for displaying those buttons. Perhaps it’s actually better to just leave the step attribute away… .

  3. Sik

    The step that adds the required property semantically ironically makes it *less* accessible, because now I can’t tell whether a field is required or not by merely looking at the form (required fields look the same as non-required fields). This is a massive usability issue, in my opinion. For the record, it’s advised against using an asterisk for indicating something is required, and to explicitly spell it out instead (e.g. by appending “(required)” to the label, possibly styled differently).

    Also, when you mark a label, clicking on it will give focus to the corresponding field (well, depends on the system and browser really, but point stands). That’s a nice thing to have even for users that don’t really need much accessibility beyond basic usability.

    • Tom

      Right. In the step you mention, I also took away the asterisk so visual users won’t see at glance that a field is required. I should mark the field as required with some visual clue. I broke the rule to always provide input for at least two senses here… .

      Explicitly spelling out “required” is not necessary anymore, in my opinion, once you use the “required” attribute which is evaluated by screen readers.

      I actually didn’t know about clicking a ! I will include that detail, since it’s another good reason for semantic markup, even it it’s “only” for normal usability and not accessibility.Thanks for the feedback!

  4. Pingback: August 11, 2013: Weekly Roundup of Web Development and Design Resources

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s