Accessible Client-side Form Validation with HTML5
Connecting labels to inputs is easy! But what about required fields, error messages, and keyboard focus?
In this three part blog series we’ll learn to make accessible forms with HTML5, WAI-ARIA, and jQuery Validation. Our strategy will be to first try validation with HTML5 in the latest browsers that support these form attributes, then we will use WAI-ARIA which works with the latest screen readers, and finally for the folks who just can’t upgrade we’ll add the jQuery Validation plugin so even IE6 users can accessibly submit forms.
Basics
The basics of form accessibility are sometimes overlooked so I’ll point them out for review.
Every. Single. Field. Needs. A. Label.
Easy enough to remember? The only bulletproof way to ensure an accessible form field is to provide an explicitly connected label using the for and id attributes.
A quick test for an explicit label is to click on the label’s text with your mouse and if focus goes into the input then they are connected. This increases the click target size and really helps everyone click those tiny checkboxes and radio buttons.
Technique for WCAG 2.0 – Success Criteria 1.1.1 (Non-text Content), 1.3.1 (Info and Relationships), 3.3.2 (Labels or Instructions), and 4.1.2 (Name, Role, Value)
H44: Using label elements to associate text labels with form controls
HTML
<label for="fname">First Name *</label> <input required type="text" name="fname" id="fname">
Output
Do this for every single field! If you don’t want to see the label then hide it off screen with CSS.
Radio Buttons & Checkboxes Need a Fieldset & Legend
HTML
<fieldset> <legend>Gender *</legend> <input type="radio" name="gender" value="male" id="male"> <label for="male">Male</label> <input type="radio" name="gender" value="female" id="female"> <label for="female">Female</label> </fieldset>
Output
Technique for WCAG 2.0 – Success Criteria 1.3.1 (Info and Relationships) and 3.3.2 (Labels or Instructions)
H71: Providing a description for groups of form controls using fieldset and legend elements
Are All Instructions Spoken?
Are input formats spoken? Did you indicate the correct format for dates, phone numbers, etc.? Again, the best way to communicate form instructions to screen readers is to place them in the label.
HTML
<label for="bday">Birthday * MM/DD/YYYY</label> <input type="text" name="bday" id="bday">
Output
Technique for WCAG 2.0 – Success Criteria 3.3.2 (Labels or Instructions) and 3.3.5 (Help)
G89: Providing expected data format and example
Required Fields
No one enjoys filling out forms! If you want to get useful data and not scare your users away then only require the least amount of fields as is necessary. Indicate the field is required by placing a red * in the label or the text (required).
Technique for WCAG 2.0 – Success Criterion 3.3.2 (Labels or Instructions)
H90: Indicating required form controls using label or legend
Error Messages
Help users out by providing useful error messages and suggestions to correct them. Placing the error in a label will cause a screen reader to speak each error as the user tabs through the form fields.
Keyboard Focus
One of the biggest failures with forms is not sending keyboard focus to the field with an error or the list of error messages. Assistive Technology users will have no idea there’s something wrong if the screen reader goes blank or their magnifier does not move focus to the error. When nothing happens after pressing the submit button they will assume your form is broken.
Techniques for WCAG 2.0 – Success Criteria 3.3.1 (Error Identification), 3.3.2 (Labels or Instructions), 3.3.3 (Error Suggestion), and 3.3.4 (Error Prevention (Legal, Financial, Data))
- G83: Providing text descriptions to identify required fields that were not completed
- G85: Providing a text description when user input falls outside the required format or values
- SCR18: Providing client-side validation and alert
- SCR32: Providing client-side validation and adding error text via the DOM
HTML5
Now that you’ve got the basics out of the way, adding HTML5 validation and usability enhancements is a piece of cake!
Required Attribute
With the HTML5 required attribute and HTML5 input types you can put the responsibility of accessible form validation on the browser developer.
HTML
<label for="lname">Last Name *</label> <input type="text" name="lname" id="lname" required> <input type="checkbox" name="tos" id="tos" required> <label for="tos">* I agree to terms of service.</label>
Of course the required attribute does not work on all browsers, Safari and Mobile Safari being the two where I miss support the most. You can read more about HTML5 browser support at The Current State of HTML5 Forms – The required Attribute by Chris Coyier (@chriscoyier) of CSS-Tricks fame. That resource is a bit out of date as support has improved in many browsers.
Input Types
HTML5 input types greatly enhance the usability and accessibility of forms on mobile devices. In iOS, the iPhone, iPad, & iPod Touch platform, most input types will display a keyboard enhanced for that data format. It is very rare to see forms in the wild take advantage of these simple usability enhancements. By default input type=text displays the normal alphabetic keyboard. If you need to type numbers, the @ symbol in an email address, or the .com for a URL extra taps are required.
Type | type=text | type=email | type=tel |
---|---|---|---|
HTML |
<label for="text">Text:</label> <input type="text" name="text" id="text"> |
<label for="email">Email:</label> <input type="email" name="email" id="email" /> |
<label for="tel">Tel:</label> <input type="tel" name="tel" id="tel" /> |
Output | |||
input type=date on iPad & iPhone
HTML
<label for="date">Date:</label> <input type="date" name="date" id="date" />
Output
Because these different keyboards and spinner controls are native to iOS they’re accessible by default. Apple’s done all the work for you.
Pattern Attribute
HTML
<label for="zip">Zip Code 5 Digits</label> <input type="number" pattern="[0-9]*" maxlength="5" min="0" name="zip" id="zip">
Output
Using the pattern attribute, pattern=”[0-9]*”, with the number input type will display the 10-digit numeric keypad similar to the tel keypad. This is much more usable than the standard number keyboard which shows a lot of keys that are not needed for simple numeric input like a Zip Code. We have fat fingers and mobile keyboards have tiny buttons. Anything you can do to increase the tap target size of a button really helps out!
HTML5Pattern.com has Regular Expression patterns that can be used to validate complex input types. These are live and can be tested in supported browsers.
You can visit HTML5 inputs and attribute support in a browser to test its support for HTML5 forms and click through all the input types. Another great page to test support for HTML5 form attributes is the jQuery Mobile – Text inputs Docs. I love the jQuery Mobile project as it does two things I’m passionate about, mobile & accessibility, very well!
Input Types Add More Stringent Validation
By adding an input type=email the browser will ask for more specific input formatting to make sure the user actually types an email address in the format name@domain.com.
If we add the required attribute to input type=number Firefox will ask for numeric data that matches the specified pattern attribute.
Simple Mobile & Screen Magnification Usability & Accessibility Enhancements
Place Label Above Input
By placing the label directly above the input you improve the experience for mobile and screen magnification users. When focus is in the input the label will no longer be cut off like in the below example of the Gmail sign up form where the label is placed to the left but cut off when viewed on an iPhone.
Position Formatting Instructions Below Input with CSS
Using CSS you can enclose formatting instructions in a span tag and position them directly under the input so they are still visible when zoomed in.
HTML
<p class="instructions-container"> <label for="zip">Zip Code <span class="instructions">5 Digits</span></label> <input type="number" pattern="[0-9]*" maxlength="5" min="0" name="zip" id="zip"> </p>
CSS
.instructions { position:relative; top: 1.6em; display:block; } .instructions-container { margin-bottom:2em; } .instructions-container label { margin-bottom:-1.2em; }
Hiding Labels Using CSS
You may want to visually hide some labels where the input might be obvious to most sighted users. We can use CSS positioning to do this. The code for this comes from the WebAIM article, CSS in Action: Invisible Content Just for Screen Reader Users.
HTML
<label for="areacode">Phone * <span class="hidden">Area Code</span></label> <input required type="tel" name="areacode" id="areacode" maxlength="3"> - <label for="threedigits" class="inline"> <span class="hidden">First Three Phone Digits</span> *</label> <input required type="tel" name="threedigits" id="threedigits" maxlength="3"> - <label for="fourdigits" class="inline"> <span class="hidden">Last Four Phone Digits</span> *</label> <input required type="tel" name="fourdigits" id="fourdigits" maxlength="4">
CSS
.hidden {position:absolute; left:-10000px; top:auto; width:1px; height:1px; overflow:hidden;}
You can disable CSS and the labels will become visible.
Next Steps – Add WAI-ARIA
In the next blog post we’ll build off the work we did here and add ARIA form and validation enhancements that are only visible to screen readers.
Links to all three posts in this series:
- Accessible Client-side Form Validation with HTML5
- Accessible Client-side Form Validation with HTML5 & WAI-ARIA
- Accessible Client-side Form Validation with HTML5, WAI-ARIA, & the jQuery Validation Plugin
Comments? Questions?
So what do you think about HTML5 form validation? Is this a viable option with the limited browser support of the required attribute? Do we still have to rely on JavaScript validation or even server-side validation since a small percent of users disable JavaScript?
Let me know if you have any suggestions for improvement or find any mistakes.
Interesting, on the ‘Leave a Reply’ form at the end of the article, I clicked on the label ‘Email (will not be published)(required)’ and it took me to a completely different email address field (which was part of an example in the article above.) I guess it goes without saying that one needs to be careful while choosing labels for form fields and has to make sure that there are no duplicates.
Hi Sree, you’re right. Thanks for the catch! I changed my example’s input id attribute to id=”email2″ and the label to for=”email2″. Working correctly now.
Nice Post,Thanks
I just have one issue not related to validation. But related to forms. Is there is simple way keep showing the Input values after the click, They disappear once you click the form.
Hi Ravi, what browser are you using? If I use Safari which does not support HTML5 validation when I click submit it will submit the non functional form and blank out the contents (if there is any).
If I use Chrome or Safari the HTML5 validation will stop the submit unless all required fields are filled. If they are filled it will submit it and then blank out the inputs. On a real world form this data would go to the sever. On these tests the form actually goes nowhere and just reloads on submit.
Glad you liked the post!
Chrome does not support maxlength & min for Number fields. In your example, you can enter a row of 9s. This is horribly inconvenient. Is there a work around that you know of? JS would be kinda hacky for what I’m doing and setting maxlength the html 4.01 way is no good either.
Hi AceoStar, good question. I looked at that zip code field which has type=”number” and maxlength=”5″ and that does not work in Chrome (Canary) or Safari on Mac. There are some similar questions on Stack Overflow about this. It actually does work fine in Firefox. Guess you just can’t have all browsers behave the way you want so the JavaScript fallback is needed. I’m sure as the browsers evolve they’ll all get on track to have good form constraints and HTML5 support.
One solution that kind of works is to add max=”99999″ and if the user goes beyond this in Chrome Canary then focus is always sent back to that field but the error message bubble does not appear. Check out Chrome Canary, there even input type=”date” has a native date picker that works with the keyboard!
A hacky way to limit it to 5 digits would be to change the input type to tel but that destroys the semantics.
Thanks for reading!
requied field will not work if multiple check box available in the form. For example, if I have 2 more checkbox and I want to select any one of the check box from there and I used required attribute in all check boxes. So it validate all the check boxes. But I want to check any one check box in this situation it will not work.
Hi shenbagakannan, it sounds like you want the checkboxes to be optional. I’m not sure if it’s possible with HTML5 to say that for example if there are 5 checkboxes then only at least one of them is required or two are required.
I think it’s pretty much an all or nothing thing. Every checkbox marked required would have to be checked.
It looks like it may be possible with the jQuery Validation plugin according to a post on Stack Overflow, Jquery Validation Plugin – Require 2 checkboxes.
Hi there,
Need some assistance about submitting a form on mobile. I have built the site for non-mobile devices AND mobile devices where people enter in selections and submit the selections to a “MAILTO:<got email addy in here". But when the person enters in their email address and selections (3 seperate fields) and then hits the "SUBMIT" button, it opens up the email client (gmail on iphone, Outlook on laptop etc) and creates it in an email that the user then has to send. I dont want that to happen, i just want it to email the form directly to the MAILTO address. Please help, and thanks 🙂
Too good 🙂
hi,
i am using some scripts freely available for my site – problem is the use syntax like:
document.field.value
– this works on their site but not in my firefox browser where i have to modify their code to:
document.getElementById(“fieldid”).value
this is too much work! how can i use the original code – why the original is not working in my browser??
check out site: http://www.123-calc.com
thanks.
Do you have a working demo? The demo form linked to does not work. Thanks!
Hello, Neat post. There is an issue together with your website in internet explorer, could test this? IE still is the marketplace chief and a big portion of people will pass over your excellent writing due to this problem.
Hi Paul, great post!
You can validate fields per group? For example: button submit1 validate input1 and input2 but button submit2 validate input3 and input4.
thanks!
Agreed, demo linked does not work. I can submit it totally empty and receive no error messages.
What’s up, I would like to subscribe for this blog to get hottest updates, so where can i do it please assist.
Great article. I live in Canada now, and the postal codes are letter and numeric. While your example of the Zip code does illustrate the point, I think developers need to be aware of differences in addressing systems. I have been excluded from filling out forms because the Zip field only accepted numbers (gas stations, too, where I can’t pay at the pump because the Zip codes on the pump only accept numbers). I suppose the solution would be to ask “what country” first, and then provide an appropriately-formatted field based on the answer? Thanks for providing the great info that you do.