How to Write Accessible Forms

How to Write Accessible Forms

This tutorial can be viewed one part at a time or all in one page.

Let's Get Started

Note that everything you see in this tutorial is something I've seen "in the wild". I'm not making any of this up.

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.

Note: As of this OS X 10.9.5, VoiceOver only reads the aria-describedby after a 5 second delay after some further information about the form control. Some browser and screen reader combos require the aria-describedby to have tabindex="-1". I did some of my own tests, or More information.

<form method="POST" action="#" name="theForm" id="theForm">
<div>Fields marked with <span class="red">*</span> are required.</div>
<label for="username">Username: <span class="red">*</span> <span class="invisibleStuff">(Required)</span></label>
<input type="text" name="uname" id="username" required>
<label for="firstname">Full Name: <span class="red">*</span> <span class="invisibleStuff">(Required)</span></label>
<input type="text" name="fname" id="firstname" required>
<label for="password1">Password: <span class="red">*</span> <span class="invisibleStuff">(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="red">*</span> <span class="invisibleStuff">(Required)</span></label>
<input type="password" name="repassword" id="password2" required aria-describedby="passwordReq">
<legend>What's your gender:</legend>
<input type="radio" name="gender" value="female">
<input type="radio" name="gender" value="male">
<label for="province">Where do you live?:</label>
<select id="province" name="prov">
<option value="false">Select Province</option>
<option value="ab">Alberta:</option>
<option value="bc">British Columbia</option>
<option value="mn">Manitoba</option>
<option value="nfld">Newfoundland</option>
<option value="nb">New Brunswick</option>
<option value="nwt">Northwest Territories</option>
<option value="ns">Nova Scotia</option>
<option value="nv">Nunavit</option>
<option value="on">Ontario</option>
<option value="pei">Prince Edward Island</option>
<option value="qc">Quebec</option>
<option value="sk">Saskatchewan</option>
<option value="yk">Yukon</option>
<label for="comments">Comments:</label>
<textarea id="comments" name="comments"></textarea>
<input type="checkbox" name="agree" required> I have read the <a href="accessibleForms/tandc.php">Terms and Conditions</a> and I agree to comply with them. <span class="red">*</span> <span class="invisibleStuff">(Required)</span></label>
<input type="submit" onclick="return validateBetterThenSubmit();" value="Submit">

See this example in action.

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