How to Write Accessible Forms

What's it all about?

When developing web applications, it's important that all users can use the application; those with low vision, those with no vision, those who are colour-blind, those who have mobility issues and can't use a mouse, those using a touch device and can't use a keyboard, and the temporarily-abled; ie: the rest of us.

The easiest disability to code for is probably colour-blindness. Just don't use colour alone to convey information. The most difficult disability would be blindness because you have to take measures to ensure that all information is presented to the user in an understandable way - usually text. So, all images that convey information must have meaningful and appropriate alternate text.

This page will attempt te teach how to write a form that will be accessible to all people.

First things First

The first thing to understand about HTML is that it is a semantic-based language. It is a mistake to think that if you want large, bold text, you should use an <h1> tag. You should use use an <h1> tag when you want a header for the whole page - regardless of what you want it to look like. You should use CSS to define what something should look like. So, it is important to understand what the meaning of each HTML tag is supposed to be used for.

The second thing to understand is that you can't determine how someone will view your site. Once upon a time it was common to see on a webpage something like "This page is best viewed using Netscape 3 with 640x480 resolution." Somehow, we just accepted that. Then came the day when people only developed for Internet Explorer 6 because it had almost 100% market share. Both of those days are long gone. Now people can view your page on a smart phone programmed by Apple, Google, Microsfot, Blackberry, etc. Or they can view it on a desktop computer with a 24" monitor. Keeping this in mind, it shouldn't be too much of a leap to understand that some will have to have a screen reader read a page aloud to them.

Thirdly, while we're talking about screen readers, it's important to know that different people use different screen readers, and different screen readers interact differently with HTML. Furthermore, different users have different settings on their screen readers. Some people will hear title attributes. Some won't. For the purposes of this page, I'll mostly be referring to NVDA because it's the screen reader I'm most familiar with.

Lastly, most desktop screen readers use keyboard shortcuts to navigate around the page. Typically, you flow from top to bottom with the arrow keys. But once a form is encountered, and the user interacts with a form control the screen reader enters into forms mode. In forms mode, keystrokes interact with the form control itself. The only two ways to navigate through a form are: 1) After every form control, press Escape to get out of forms mode, navigate to the next form control with the arrow key, then enter forms mode again; or 2) press Tab to send focus from form control to form control until you get to the end of a form. For the purposes of this page, we'll assume that most users would use the second method because the first one would be a pain in the arse.

So, with these things in mind....

Let's Get Started

Building A Form For Input

We will build a registration form and make it accessible. A login form would consist of fields for a username, a full name, a password, retype your password, a Terms and Conditions checkbox, and a submit button. And just for fun we'll add gender and province select controls.

Don't Re-invent The Wheel

<form method="POST" action="register.page" name="theForm" id="theForm">
<span style="color: #FF0000; background-color: #000000;"><b>Username:</b></span>
<span onkeypress="addText(this);"></span>
<br>
<span style="color: #FF0000; background-color: #000000;"><b>Full Name:</b></span>
<span onkeypress="addText(this);">Full names must consist only of letters, a dash, and no more than 3 spaces.</span>
<br>
<span style="color: #FF0000; background-color: #000000;"><b>Password:</b></span>
<span onkeypress="addPasswordText(this);"></span>
<div>Passwords should be at least 8 characters, contain numbers, upper and lower case letters and a special character. This way it will be hard for you to remember, but easy for a computer to guess.</div>
<span style="color: #FF0000; background-color: #000000;"><b>Re-type Password:</b></span>
<span onkeypress="addPasswordText(this);"></span>
<br> <span><b>What's your gender:</b></span>
<br>
<img src="cirlce.jpg" onclick="toggleCircle(this);">
<span><b>Female:</b></span>
<br>
<img src="cirlce.jpg" onclick="toggleCircle(this);">
<span><b>Male:</b></span>
<br>
<span><b>Where do you live?:</b></span>
<br>
<img src="cirlce.jpg" onclick="toggleCircle(this);">
<span><b>Alberta:</b></span>
<br>
<img src="cirlce.jpg" onclick="toggleCircle(this);">
<span><b>British Columbia</b></span>
<br>
....
<br> <span>Comments:</span>
<div onclick="addText(this);">Enter comments here.</div>
<img src="sqare.jpg" onlick="toggleSquare(this);"> <span style="color: #FF0000; background-color: #000000;"><b>I have read the <a href="t_and_c.html">Terms and Conditions</a> and I agree to comply with them.</span>
<div class="button" onclick="document.theForm.submit();">Submit</div>
</form>
<div>All required fields were in red.</div>

Okay, if you do this, you deserve to have every disability in the book thrust on you. It is a giant middle-finger to everyone with a disability, to anyone with a browser that stucks at interpreting Javascript, and to all competent web developers everywhere. And I hate you.

In this example I used spans with event handlers to modify their own content when a key is pressed. The problem is that you can't focus these items. They require Javascript to be turned on. While WCAG 2.0 does not require a Javascript-less interface, it's generally good practice to not require it more than necessary. Progressive enhancement and all that.

So, let's try not to re-invent the wheel. HTML since time immemorial has provided a text input, a password input, checkboxes, radio buttons, etc.. So, it should look like:

<form method="POST" action="register.page" name="theForm" id="theForm">
<span style="color: #FF0000; background-color: #000000;"><b>Username:</b></span>
<input type="text" name="uname">
<br>
<span style="color: #FF0000; background-color: #000000;"><b>Full Name:</b></span>
<input type="text" name="fname" placeholder="Full names must consist only of letters, a dash, and no more than 3 spaces.">
<br>
<span style="color: #FF0000; background-color: #000000;"><b>Password:</b></span>
<input type="password" name="password">
<div>Passwords should be at least 8 characters, contain numbers, upper and lower case letters and a special character. This way it will be hard for you to remember, but easy for a computer to guess.</div>
<span style="color: #FF0000; background-color: #000000;"><b>Re-type Password:</b></span>
<input type="password" name="rePassword">
<br> <span><b>What's your gender:</b></span>
<br>
<input type="radio" name="gender">
<span><b>Female:</b></span>
<br>
<input type="radio" name="gender">
<span><b>Male:</b></span>
<br>
<span><b>Where do you live?:</b></span>
<br>
<input type="radio" name="province">
<span><b>Alberta:</b></span>
<br>
<input type="radio" name="province">
<span><b>British Columbia</b></span>
<br>
....
<br> <span>Comments:</span>
<textarea onblur="document.theForm.submit();">Enter comments here.</textarea>
<input type="checkbox" name="TandCAgree">
<span style="color: #FF0000; background-color: #000000;"><b>I have read the <a href="t_and_c.html">Terms and Conditions</a> and I agree to comply with them.</span>
<input type="button" onclick="document.theForm.submit();" value="Submit">
</form>
<div>All required fields were in red.</div>

Even if you wanted to register, a blind user wouldn't hear very many useful instructions. They might hear something like "Username, Full Name, Editable, Editable password, password, clickable unselected clickable unselected (repeated for quite some time) Enter Comments Here.". Not very useful, is it?

While we're using native HTML elements, please get rid of that onblur event handler. What if a user uses shift-tab to go back from Comments to Province to make a correction? This idiotic form will submit before they can do anything! Again, using an HTML submit button is the way to go.

(Yes, you could go with a <button> with an event handler. But, again WHY? If you do this without good reason, you officially suck and should probably start looking for a new career.

<form method="POST" action="register.page" name="theForm" id="theForm">
<span style="color: #FF0000; background-color: #000000;"><b>Username:</b></span>
<input type="text" name="uname">
<br>
<span style="color: #FF0000; background-color: #000000;"><b>Full Name:</b></span>
<input type="text" name="fname" placeholder="Full names must consist only of letters, a dash, and no more than 3 spaces.">
<br>
<span style="color: #FF0000; background-color: #000000;"><b>Password:</b></span>
<input type="password" name="password">
<div>Passwords should be at least 8 characters, contain numbers, upper and lower case letters and a special character. This way it will be hard for you to remember, but easy for a computer to guess.</div>
<span style="color: #FF0000; background-color: #000000;"><b>Re-type Password:</b></span>
<input type="password" name="rePassword">
<br> <span><b>What's your gender:</b></span>
<br>
<input type="radio" name="gender">
<span><b>Female:</b></span>
<br>
<input type="radio" name="gender">
<span><b>Male:</b></span>
<br>
<span><b>Where do you live?:</b></span>
<br>
<input type="radio" name="province">
<span><b>Alberta:</b></span>
<br>
<input type="radio" name="province">
<span><b>British Columbia</b></span>
<br>
....
<br> <span>Comments:</span>
<textarea name="comments" onblur="document.theForm.submit();">Enter comments here.</textarea>
<input type="checkbox" name="TandCAgree">
<span style="color: #FF0000; background-color: #000000;"><b>I have read the <a href="t_and_c.html">Terms and Conditions</a> and I agree to comply with them.</span>
<input type="button" onclick="document.theForm.submit();" value="Submit">
</form>
<div>All required fields were in red.</div>

Use Correct HTML Elements

Okay, so the form we have now is using correct input types and a submit button. A keyboard-only visual user will be able to use this form. But a blind user will still be lost.

Thankfully HTML provides labels. When a screen reader gets to a form control while in forms mode, it reads the label aloud to tell the user what the form control is.

A label is associate with one and only one form control. Some form controls (buttons, for example) have implicit labels. The hidden form control does not need a label. But checkboxes, radio buttons, textareas, textboxes, drop-down boxes, etc. all require lables.

Labels can be associated with form controls explicitly or implicitly. Implicit associations are usually used for radio buttons and checkboxes. Having the form control as a child element of the label makes an implicit association. Using the for attribute in the label element explicitly associates the label with a form control. The form control's id value is the calue for the for attribute in the label.

So, let's re-do the above form using labels instead of spans. The submit button will use the value attribute for the label. The other two will be explicitly associated.

<form method="POST" action="register.page" name="theForm" id="theForm">
<label for="username" style="color: #FF0000; background-color: #000000;"><b>Username:</b></label>
<input type="text" name="uname" id="username">
<br>
<label for="fname" style="color: #FF0000; background-color: #000000;"><b>Full Name:</b></span>
<input type="text" name="fname" id="fname" placeholder="Full names must consist only of letters, a dash, and no more than 3 spaces.">
<br>
<label for="password1" style="color: #FF0000; background-color: #000000;"><b>Password:</b></label>
<input type="password" name="password" id="password1">
<div>Passwords should be at least 8 characters, contain numbers, upper and lower case letters and a special character. This way it will be hard for you to remember, but easy for a computer to guess.</div>
<label for="password2" style="color: #FF0000; background-color: #000000;"><b>Re-type Password:</b></label>
<input type="password" name="rePassword" id="password2">
<br> <span><b>What's your gender:</b></span>
<br>
<label> <input type="radio" name="gender">
<b>Female:</b></label>
<br>
<label> <input type="radio" name="gender">
<b>Male:</b></label>
<br>
<span><b>Where do you live?:</b></span>
<br>
<label> <input type="radio" name="province">
<b>Alberta:</b></label>
<br>
<label> <input type="radio" name="province">
<b>British Columbia</b></label>
<br>
....
<br> <label for="commentsTA">Comments:</label>
<textarea name="comments" id="comments">Enter comments here.</textarea>
<label> <input type="checkbox" name="TandCAgree">
<span style="color: #FF0000; background-color: #000000;"><b>I have read the <a href="t_and_c.html">Terms and Conditions</a> and I agree to comply with them.</span></label>
<input type="submit" value="Submit">
</form>
<div>All required fields were in red.</div>

Now a screen reader will read out something like: "Username editable, Full Name editable, Password Editable password, Re-type Password editable password, Female clickable unselected Male clickable unselected Female clickable unselected Male clickable unselected " followed by all the provinces and territories at least once with "unselected" followed by "Comments, Enter comments here, clickable unchecked I have read the Link Terms and Conditions and I agree to comply with them, Submit clickable."

Know when to use radio buttons and when to use a drop-down

We're on our way, but the way it reads out all of those provinces is annoying. And there's only ten of them (and three territories). In the states, there are fifty of them. There has to be a better way! And there is. A select, or drop-down box. Radio buttons are okay when there are only two or three options, like with gender. The form only gives two options. Whenever one is selected, the whole list is read by the screen reader. Not a problem for two items, but a big problem for longer lists. So, for provinces (or states) we'll use a select box.

<form method="POST" action="register.page" name="theForm" id="theForm">
<label for="username" style="color: #FF0000; background-color: #000000;"><b>Username:</b></label>
<input type="text" name="uname" id="username">
<br>
<label for="fname" style="color: #FF0000; background-color: #000000;"><b>Full Name:</b></span>
<input type="text" name="fname" id="fname" placeholder="Full names must consist only of letters, a dash, and no more than 3 spaces.">
<br>
<label for="password1" style="color: #FF0000; background-color: #000000;"><b>Password:</b></label>
<input type="password" name="password" id="password1">
<div>Passwords should be at least 8 characters, contain numbers, upper and lower case letters and a special character. This way it will be hard for you to remember, but easy for a computer to guess.</div>
<label for="password2" style="color: #FF0000; background-color: #000000;"><b>Re-type Password:</b></label>
<input type="password" name="rePassword" id="password2">
<br> <span><b>What's your gender:</b></span>
<br>
<label> <input type="radio" name="gender">
<b>Female:</b></label>
<br>
<label> <input type="radio" name="gender">
<b>Male:</b></label>
<br>
<label for="province"><b>Where do you live?:</b></label>
<select name="province" id="province">
<input type="radio" name="province">
<option> </option>
<option value="alberta">Alberta</option>
<option value="bc">British Columbia</option>
....
</select>
<br> <label for="commentsTA">Comments:</label>
<textarea name="comments" id="comments">Enter comments here.</textarea>
<label> <input type="checkbox" name="TandCAgree">
<span style="color: #FF0000; background-color: #000000;"><b>I have read the <a href="t_and_c.html">Terms and Conditions</a> and I agree to comply with them.</span></label>
<input type="submit" value="Submit">
</form>
<div>All required fields were in red.</div>

Almost! Notice the first item in the drop-down is empty? That should never be. If you don't want the first itme being one that you can select, then put a place-holder in there, and check for the value in form validation after submission.

<form method="POST" action="register.page" name="theForm" id="theForm">
<label for="username" style="color: #FF0000; background-color: #000000;"><b>Username:</b></label>
<input type="text" name="uname" id="username">
<br>
<label for="fname" style="color: #FF0000; background-color: #000000;"><b>Full Name:</b></span>
<input type="text" name="fname" id="fname" placeholder="Full names must consist only of letters, a dash, and no more than 3 spaces.">
<br>
<label for="password1" style="color: #FF0000; background-color: #000000;"><b>Password:</b></label>
<input type="password" name="password" id="password1">
<div>Passwords should be at least 8 characters, contain numbers, upper and lower case letters and a special character. This way it will be hard for you to remember, but easy for a computer to guess.</div>
<label for="password2" style="color: #FF0000; background-color: #000000;"><b>Re-type Password:</b></label>
<input type="password" name="rePassword" id="password2">
<br> <span><b>What's your gender:</b></span>
<br>
<label> <input type="radio" name="gender">
<b>Female:</b></label>
<br>
<label> <input type="radio" name="gender">
<b>Male:</b></label>
<br>
<label for="province"><b>Where do you live?:</b></label>
<select name="province" id="province">
<input type="radio" name="province">
<option value="unselected">- Select Province -</option>
<option value="alberta">Alberta</option>
<option value="bc">British Columbia</option>
....
</select>
<br> <label for="commentsTA">Comments:</label>
<textarea name="comments" id="comments">Enter comments here.</textarea>
<label> <input type="checkbox" name="TandCAgree">
<span style="color: #FF0000; background-color: #000000;"><b>I have read the <a href="t_and_c.html">Terms and Conditions</a> and I agree to comply with them.</span></label>
<input type="submit" value="Submit">
</form>
<div>All required fields were in red.</div>

What about 'in-between' text?

Now a screen reader will read out something like: "Username editable, Fullname, Password Editable password, Re-type Password editable password, Female clickable unselected Male clickable unselected Female clickable unselected Male clickable unselected, Where do you live? Select Province Drop-down, Comments, Enter comments here, clickable unchecked I have read the Link Terms and Conditions and I agree to comply with them, Submit clickable."

If you're paying close attention you'll see it's missing a few things like password requirements, "What's your Gender?", and "All required fields were in red." First, any instructions about the form should come before the form! So we'll just move that up top.

As for the "What's your gender?", well, this could have been in the User Proper HTML section. When you have a group of form controls that are closely related (like a group of radio buttons), or a group of form controls that have the same text to "bind them all together" (if you will), then a fieldset and legend are what you're looking for. The fieldset is what binds them all together, and the legend is what is read before each label.

<div>All required fields are in red.</div> <form method="POST" action="register.page" name="theForm" id="theForm">
<label for="username" style="color: #FF0000; background-color: #000000;"><b>Username:</b></label>
<input type="text" name="uname" id="username">
<br>
<label for="fname" style="color: #FF0000; background-color: #000000;"><b>Full Name:</b></span>
<input type="text" name="fname" id="fname" placeholder="Full names must consist only of letters, a dash, and no more than 3 spaces.">
<br>
<label for="password1" style="color: #FF0000; background-color: #000000;"><b>Password:</b></label>
<input type="password" name="password" id="password1">
<div>Passwords should be at least 8 characters, contain numbers, upper and lower case letters and a special character. This way it will be hard for you to remember, but easy for a computer to guess.</div>
<label for="password2" style="color: #FF0000; background-color: #000000;"><b>Re-type Password:</b></label>
<input type="password" name="rePassword" id="password2">
<fieldset> <legend><b>What's your gender:</b></legend>
<br>
<label> <input type="radio" name="gender">
<b>Female:</b></label>
<br>
<label> <input type="radio" name="gender">
<b>Male:</b></label>
</fieldset>
<label for="province"><b>Where do you live?:</b></label>
<select name="province" id="province">
<input type="radio" name="province">
<option value="unselected">- Select Province -</option>
<option value="alberta">Alberta</option>
<option value="bc">British Columbia</option>
....
</select>
<br> <label for="commentsTA">Comments:</label>
<textarea name="comments" id="comments">Enter comments here.</textarea>
<label> <input type="checkbox" name="TandCAgree">
<span style="color: #FF0000; background-color: #000000;"><b>I have read the <a href="t_and_c.html">Terms and Conditions</a> and I agree to comply with them.</span></label>
<input type="submit" value="Submit">
</form>

Now a screen reader will read out something like: "All required fields are in red. Username editable, Full Name editable, Password Editable password, Re-type Password editable password, What's your gender? Female clickable unselected Male clickable unselected Female clickable unselected Male clickable unselected, Where do you live? Select Province Drop-down, Comments, Enter comments here, clickable unchecked I have read the Link Terms and Conditions and I agree to comply with them, Submit clickable."

Now we're getting somwhere! But we're still missing the password instructions. The simplest, most basic way is to make it selectable with a tabindex="0". (There is a more advanced way, but I'll deal with that later.)

The reason we use tabindex="0" is that it makes otherwise non-focusable text focusable. As the form is right now, after you tab out of Password, you tab into Re-type Password.

<div>All required fields are in red.</div> <form method="POST" action="register.page" name="theForm" id="theForm">
<label for="username" style="color: #FF0000; background-color: #000000;"><b>Username:</b></label>
<input type="text" name="uname" id="username">
<br>
<label for="fname" style="color: #FF0000; background-color: #000000;"><b>Full Name:</b></span>
<input type="text" name="fname" id="fname" placeholder="Full names must consist only of letters, a dash, and no more than 3 spaces.">
<br>
<label for="password1" style="color: #FF0000; background-color: #000000;"><b>Password:</b></label>
<input type="password" name="password" id="password1">
<div tabindex="0">Passwords should be at least 8 characters, contain numbers, upper and lower case letters and a special character. This way it will be hard for you to remember, but easy for a computer to guess.</div>
<label for="password2" style="color: #FF0000; background-color: #000000;"><b>Re-type Password:</b></label>
<input type="password" name="rePassword" id="password2">
<fieldset> <legend><b>What's your gender:</b></legend>
<br>
<label> <input type="radio" name="gender">
<b>Female:</b></label>
<br>
<label> <input type="radio" name="gender">
<b>Male:</b></label>
</fieldset>
<label for="province"><b>Where do you live?:</b></label>
<select name="province" id="province">
<input type="radio" name="province">
<option value="unselected">- Select Province -</option>
<option value="alberta">Alberta</option>
<option value="bc">British Columbia</option>
....
</select>
<br> <label for="commentsTA">Comments:</label>
<textarea name="comments" id="comments">Enter comments here.</textarea>
<label> <input type="checkbox" name="TandCAgree">
<span style="color: #FF0000; background-color: #000000;"><b>I have read the <a href="t_and_c.html">Terms and Conditions</a> and I agree to comply with them.</span></label>
<input type="submit" value="Submit">
</form>

Now a screen reader will read out something like: "All required fields are in red. Username editable, Full Name editable, Password Editable password, Passwords should be at least 8 characters, contain numbers, upper and lower case letters and a special character. This way it will be hard for you to remember, but easy for a computer to guess. Re-type Password editable password, What's your gender? Female clickable unselected Male clickable unselected Female clickable unselected Male clickable unselected, Where do you live? Select Province Drop-down, Comments, Enter comments here, clickable unchecked I have read the Link Terms and Conditions and I agree to comply with them, Submit clickable."

Colouring

Okay, let's take care of some styling. As it is, we're using pure red on white for the required fields. Low vision people will have trouble with that contrast. Colourblind people will be all like "Which ones are red?" So, it's best to just put the text "(Required)" in the fields. If you don't wan't to have that written out, put it in a span and use styling to make it invisible to us, but readable to screen readers. (display: none; hides stuff from screen readers.) Also, don't forget to use the HTML5 required attribute.

And while we're at it, please use CSS to define what should be bold and big, etc.

<form method="POST" action="register.page" name="theForm" id="theForm">
<label for="username">Username: * <span class="invisible">Required</span></label>
<input type="text" name="uname" id="username" required>
<br>
<label for="fname">Full Name: * <span class="invisible">Required</span></label>
<input type="text" name="fname" id="fname"> placeholder="Full names must consist only of letters, a dash, and no more than 3 spaces."
<br>
<label for="password1">Password: * <span class="invisible">Required</span></label>
<input type="password" name="password" id="password1" required>
<div tabindex="0">Passwords should be at least 8 characters, contain numbers, upper and lower case letters and a special character. This way it will be hard for you to remember, but easy for a computer to guess.</div>
<label for="password2">Re-type Password: * <span class="invisible">Required</span></label>
<input type="password" name="rePassword" id="password2" required>
<fieldset> <legend><b>What's your gender:</b></legend>
<br>
<label> <input type="radio" name="gender">
Female:</label>
<br>
<label> <input type="radio" name="gender">
Male:</label>
</fieldset>
<label for="province">Where do you live?:</label>
<select name="province" id="province">
<input type="radio" name="province">
<option value="unselected">- Select Province -</option>
<option value="alberta">Alberta</option>
<option value="bc">British Columbia</option>
....
</select>
<br> <label for="commentsTA">Comments:</label>
<textarea name="comments" id="comments">Enter comments here.</textarea>
<label> <input type="checkbox" name="TandCAgree">
I have read the <a href="t_and_c.html">Terms and Conditions</a> and I agree to comply with them. * <span class="invisible">Required</span></label>
<input type="submit" value="Submit">
</form>

Get rid of extraneous text

In the textarea there is some text "Enter comments here." That's called 'placeholder text', as is the text in the placeholder attribute. The problem with the placeholder attribute is that the text only appears when the user hasn't entered any data. So, if they forget what they're supposed to be entering, then they have to delete everything to see the instructions, then retype it in. Also, the default style of a lot of browsers makes it a light grey, giving much too low of a contrast ratio.

It's unnecessary and confusing to screen reader users. Get rid of it.

<form method="POST" action="register.page" name="theForm" id="theForm">
<label for="username">Username: * <span class="invisible">Required</span></label>
<input type="text" name="uname" id="username" required>
<br>
<label for="fname">Full Name: * <span class="invisible">Required</span></label>
<input type="text" name="fname" id="fname" title="Full names must consist only of letters, a dash, and no more than 3 spaces.">
<br>
<label for="password1">Password: * <span class="invisible">Required</span></label>
<input type="password" name="password" id="password1" required>
<div tabindex="0">Passwords should be at least 8 characters, contain numbers, upper and lower case letters and a special character. This way it will be hard for you to remember, but easy for a computer to guess.</div>
<label for="password2">Re-type Password: * <span class="invisible">Required</span></label>
<input type="password" name="rePassword" id="password2" required>
<fieldset> <legend><b>What's your gender:</b></legend>
<br>
<label> <input type="radio" name="gender">
Female:</label>
<br>
<label> <input type="radio" name="gender">
Male:</label>
</fieldset>
<label for="province">Where do you live?:</label>
<select name="province" id="province">
<input type="radio" name="province">
<option value="unselected">- Select Province -</option>
<option value="alberta">Alberta</option>
<option value="bc">British Columbia</option>
....
</select>
<br> <label for="commentsTA">Comments:</label>
<textarea name="comments" id="comments"></textarea>
<label> <input type="checkbox" name="TandCAgree">
I have read the <a href="t_and_c.html">Terms and Conditions</a> and I agree to comply with them. * <span class="invisible">Required</span></label>
<input type="submit" value="Submit">
</form>

The title Attribute

You'll see in the previous example I replaced the placeholder attribute in the Full Name field with a title attribute. Now that bit of text will only be seen when a user hovers over that textbox. Keyboard-only visual users, and mobile will never see it. Screen reader users may or may not hear it, depending on the screen reader, and settings. The title attribute is best left to webcomics like XKCD and Amazing Super Powers to make humourous mouse-overs.

So, to fix the Full Name field, we'll just take that text right out and leave it as part of an error message later on. Most people won't have to be told that a name consists of letters, and dahses. And very few people will have more than 4 names to enter.

<form method="POST" action="register.page" name="theForm" id="theForm">
<label for="username">Username: * <span class="invisible">Required</span></label>
<input type="text" name="uname" id="username" required>
<br>
<label for="fname">Full Name: * <span class="invisible">Required</span></label>
<input type="text" name="fname" id="fname">
<br>
<label for="password1">Password: * <span class="invisible">Required</span></label>
<input type="password" name="password" id="password1" required>
<div tabindex="0">Passwords should be at least 8 characters, contain numbers, upper and lower case letters and a special character. This way it will be hard for you to remember, but easy for a computer to guess.</div>
<label for="password2">Re-type Password: * <span class="invisible">Required</span></label>
<input type="password" name="rePassword" id="password2" required>
<fieldset> <legend><b>What's your gender:</b></legend>
<br>
<label> <input type="radio" name="gender">
Female:</label>
<br>
<label> <input type="radio" name="gender">
Male:</label>
</fieldset>
<label for="province">Where do you live?:</label>
<select name="province" id="province">
<input type="radio" name="province">
<option value="unselected">- Select Province -</option>
<option value="alberta">Alberta</option>
<option value="bc">British Columbia</option>
....
</select>
<br> <label for="commentsTA">Comments:</label>
<textarea name="comments" id="comments"></textarea>
<label> <input type="checkbox" name="TandCAgree">
I have read the <a href="t_and_c.html">Terms and Conditions</a> and I agree to comply with them. * <span class="invisible">Required</span></label>
<input type="submit" value="Submit">
</form>

What about ARIA?

ARIA stands for Accessible Rich Internet Applications. It's basically a set of HTML attributes to be used specifically for adaptive technologies like screen readers. Since support of ARIA can be sketchy at times, if there's a way to accomplish something using native HTML, use the HTML and not the ARIA. In time many AIRA attributes will be replaced by native HTML. Don't use aria-labelledby when you can just use a <label>.

So remember I said there was a more advanced way to make the password requirements readable by a screen reader? ARIA is that more advanced method. We'll give that section an id and in the password field(s) we'll use aria-describedby.

<form method="POST" action="register.page" name="theForm" id="theForm">
<label for="username">Username: * <span class="invisible">Required</span></label>
<input type="text" name="uname" id="username" required>
<br>
<label for="fname">Full Name: * <span class="invisible">Required</span></label>
<input type="text" name="fname" id="fname">
<br>
<label for="password1">Password: * <span class="invisible">Required</span></label>
<input type="password" name="password" id="password1" required aria-describedby="passwordReq">
<div tabindex="0" id="passwordReq">Passwords should be at least 8 characters, contain numbers, upper and lower case letters and a special character. This way it will be hard for you to remember, but easy for a computer to guess.</div>
<label for="password2">Re-type Password: * <span class="invisible">Required</span></label>
<input type="password" name="rePassword" id="password2" required aria-describedby="passwordReq">
<fieldset> <legend><b>What's your gender:</b></legend>
<br>
<label> <input type="radio" name="gender">
Female:</label>
<br>
<label> <input type="radio" name="gender">
Male:</label>
</fieldset>
<label for="province">Where do you live?:</label>
<select name="province" id="province">
<input type="radio" name="province">
<option value="unselected">- Select Province -</option>
<option value="alberta">Alberta</option>
<option value="bc">British Columbia</option>
....
</select>
<br> <label for="commentsTA">Comments:</label>
<textarea name="comments" id="comments"></textarea>
<label> <input type="checkbox" name="TandCAgree">
I have read the <a href="t_and_c.html">Terms and Conditions</a> and I agree to comply with them. * <span class="invisible">Required</span></label>
<input type="submit" value="Submit">
</form>

Notice I left the tabindex="0" in there? I could have taken it out, but what if someone's using a screen reader and browser combo that doesn't do well with aria? This way they get it for sure. It will be read with each password box and in between them in the tab order. (I can use Javascript to remove the tabindex="0" upon page load if I want.)

Don't forget the errors!

Inevitably a user will put bad data into a form, and those errors need to be caught and reported to the user. And the user may need some help to fix the error.

Reporting Errors

In the form we've been using thus far, let's assume the user entered a bad password; one that did not conform, a bad Full name, and they did not retype their password at all.

Your form data should be validated at the server for sure. If you want to validate in the browser with Javascript, that's fine too. You need to validate at the server for security purposes. If the submitted form has invalid data, then the user should be sent back to the page where errors are listed in a list of links to the fields that contain the errors. As for accessibility, there's nothing wrong with this approach, but when the page re-loads, the focus will be at the top of the page and a blind user will have to go through the page until they get to the errors so they can fix them and re-submit. The only accessibility consideration here is that you should probably add the word "Error" to the page title so a blind user will hear that they're on the same page, but there are errors to be fixed.

For the remainder of the tutorial we will assume client-side Javascript form validation.

Now that the form has been built, let's deal with some Javascript and pseudo code to make the form function in an accessible and user friendly way.

theForm.onSubmit = function () { return validateForm(theForm); };

If you use client-side validation there is really only one consideration to be made that doesn't apply to server-side validation: focus. In the above code, if the form doesn't validate, the form won't submit, but nothing else happens. Everyone will just think the form isn't working and may give up. We need to tell the user that their data has errors.

theForm.onSubmit = function () { if (validateForm(theForm)) { return true; } else { addErrorMessages(); } }; function addErrorMessages () { var theForm = document.getElementById("theForm"); var errorMsg = "<div class="errorMessage">There are errors in the form</div> theForm.innerHTML = errorMsg + theFrom.innerHTML; }

In the above example, a message will appear above the form indicating that there are error messages and the form won't submit. However, a blind user will have no idea what's going on. To fix this we need to throw the focus somewhere so they know what's going on. (Don't forget to set the tabindex to either 0 or -1. -1 allows Javascript to send focus to it, but it won't receive focus when a user tabs through the page.)

theForm.onSubmit = function () { if (validateForm(theForm)) { return true; } else { addErrorMessages(); } }; function addErrorMessages () { var theForm = document.getElementById("theForm"); var errorMsg = "<div id=\"errorMsg\" class=\"errorMessage\" tabindex=\"-1\">There are errors in the form</div> theForm.innerHTML = errorMsg + theFrom.innerHTML; errorMsg.focus(); }

From here we'll show the HTML that the Javascript would create.

It's a start. But what are the specific errors? Which fields? It's a best practice to create a section before the form with a list of links to each form field with an error where the link text explains the errors, with those errors added to the label text.

<form method="POST" action="register.page" name="theForm" id="theForm">
<div id="errorMsg" class="errorMessage" tabindex="-1">There are errors in the form.</div>
<label for="username">Username: * <span class="invisible">Required</span></label>
<input type="text" name="uname" id="username" required>
<br>
<label for="fname">Full Name: * <span class="invisible">Required</span></label>
<input type="text" name="fname" id="fname">
<br>
<span class="error">The Full Name should consist only of letters, dashes, and no more than three spaces.</span> <br>
<label for="password1">Password: * <span class="invisible">Required</span></label>
<input type="password" name="password" id="password1" required aria-describedby="passwordReq">
<br>
<span class="error">The password should be at least 8 characters, contain numbers, upper and lower case letters and a special character.</span> <div tabindex="0" id="passwordReq">Passwords should be at least 8 characters, contain numbers, upper and lower case letters and a special character. This way it will be hard for you to remember, but easy for a computer to guess.</div>
<label for="password2">Re-type Password: * <span class="invisible">Required</span></label>
<input type="password" name="rePassword" id="password2" required aria-describedby="passwordReq">
<br>
<span class="error">You need to re-type your password exactly as in the previous field.</span> <fieldset> <legend><b>What's your gender:</b></legend>
<br>
<label> <input type="radio" name="gender">
Female:</label>
<br>
<label> <input type="radio" name="gender">
Male:</label>
</fieldset>
<label for="province">Where do you live?:</label>
<select name="province" id="province">
<input type="radio" name="province">
<option value="unselected">- Select Province -</option>
<option value="alberta">Alberta</option>
<option value="bc">British Columbia</option>
....
</select>
<br> <label for="commentsTA">Comments:</label>
<textarea name="comments" id="comments"></textarea>
<label> <input type="checkbox" name="TandCAgree">
I have read the <a href="t_and_c.html">Terms and Conditions</a> and I agree to comply with them. * <span class="invisible">Required</span></label>
<input type="submit" value="Submit">
</form>

If you've been paying attention, you'll see something wrong with this form. The error messages won't be read by a screen reader. Make the error messages part of the <label>.

<form method="POST" action="register.page" name="theForm" id="theForm">
<div id="errorMsg" class="errorMessage" tabindex="-1">There are errors in the form.</div>
<label for="username">Username: * <span class="invisible">Required</span></label>
<input type="text" name="uname" id="username" required>
<br>
<label for="fname">Full Name: * <span class="invisible">Required</span> <br>
<span class="error">The Full Name should consist only of letters, dashes, and no more than three spaces.</span> </label>
<input type="text" name="fname" id="fname">
<br>
<label for="password1">Password: * <span class="invisible">Required</span> <br>
<span class="error">The password should be at least 8 characters, contain numbers, upper and lower case letters and a special character.</span> </label>
<input type="password" name="password" id="password1" required aria-describedby="passwordReq">
<div tabindex="0" id="passwordReq">Passwords should be at least 8 characters, contain numbers, upper and lower case letters and a special character. This way it will be hard for you to remember, but easy for a computer to guess.</div>
<label for="password2">Re-type Password: * <span class="invisible">Required</span> <br>
<span class="error">You need to re-type your password exactly as in the previous field.</span> </label>
<input type="password" name="rePassword" id="password2" required aria-describedby="passwordReq">
<fieldset> <legend><b>What's your gender:</b></legend>
<br>
<label> <input type="radio" name="gender">
Female:</label>
<br>
<label> <input type="radio" name="gender">
Male:</label>
</fieldset>
<label for="province">Where do you live?:</label>
<select name="province" id="province">
<input type="radio" name="province">
<option value="unselected">- Select Province -</option>
<option value="alberta">Alberta</option>
<option value="bc">British Columbia</option>
....
</select>
<br> <label for="commentsTA">Comments:</label>
<textarea name="comments" id="comments"></textarea>
<label> <input type="checkbox" name="TandCAgree">
I have read the <a href="t_and_c.html">Terms and Conditions</a> and I agree to comply with them. * <span class="invisible">Required</span></label>
<input type="submit" value="Submit">
</form>

I think at this point we've reached WCAG 2.0 AA compliance. But there is one more piece to add for a best-practice. List the errors in a list of links pointing to the appropriate field.

<form method="POST" action="register.page" name="theForm" id="theForm">
<div id="errorMsg" class="errorMessage" tabindex="-1">There are errors in the form.
<ol> <li><a href="#fname">The Full Name should consist only of letters, dashes, and no more than three spaces.</a></li>
<li><a href="#password">The password should be at least 8 characters, contain numbers, upper and lower case letters and a special character.</a></li>
<li><a href="#password1">You need to re-type your password exactly as in the previous field.</a></li>
</ol> </div> <label for="username">Username: * <span class="invisible">Required</span></label>
<input type="text" name="uname" id="username" required>
<br>
<label for="fname">Full Name: * <span class="invisible">Required</span> <br>
<span class="error">The Full Name should consist only of letters, dashes, and no more than three spaces.</span> </label>
<input type="text" name="fname" id="fname">
<br>
<label for="password1">Password: * <span class="invisible">Required</span> <br>
<span class="error">The password should be at least 8 characters, contain numbers, upper and lower case letters and a special character.</span> </label>
<input type="password" name="password" id="password1" required aria-describedby="passwordReq">
<div tabindex="0" id="passwordReq">Passwords should be at least 8 characters, contain numbers, upper and lower case letters and a special character. This way it will be hard for you to remember, but easy for a computer to guess.</div>
<label for="password2">Re-type Password: * <span class="invisible">Required</span> <br>
<span class="error">You need to re-type your password exactly as in the previous field.</span> </label>
<input type="password" name="rePassword" id="password2" required aria-describedby="passwordReq">
<fieldset> <legend><b>What's your gender:</b></legend>
<br>
<label> <input type="radio" name="gender">
Female:</label>
<br>
<label> <input type="radio" name="gender">
Male:</label>
</fieldset>
<label for="province">Where do you live?:</label>
<select name="province" id="province">
<input type="radio" name="province">
<option value="unselected">- Select Province -</option>
<option value="alberta">Alberta</option>
<option value="bc">British Columbia</option>
....
</select>
<br> <label for="commentsTA">Comments:</label>
<textarea name="comments" id="comments"></textarea>
<label> <input type="checkbox" name="TandCAgree">
I have read the <a href="t_and_c.html">Terms and Conditions</a> and I agree to comply with them. * <span class="invisible">Required</span></label>
<input type="submit" value="Submit">
</form>