I'm doing research for my upcoming HTML5 presentation at cfObjective. One of the areas that I find most interesting is updates to forms. I'm probably biased since I've worked on so many web applications as opposed to front end/marketing type sites, but I tend to think forms are pretty critical. (And no big surprise - my other favorite areas of HTML5 involve data and networking.) I've previously looked at updates to form fields, but I had not really spent a lot of time looking at validation. I spent some time on it this week and have come away pretty damn impressed. Here is the first in a series of blog entries planned on the topic.
In today's blog entry, I want to look at validation at the tag level. Tomorrow's entry (well, the next entry) will look at some of the JavaScript involved, but I was very surprised by how much you could do without writing a line of JavaScript. At a high level, validation in HTML5 comes down to three features:
- Adding a required attribute to a form field will make it required. Duh.
- Adding a type attribute to a form field will make the form check your input and ensure it matches the type.
- And finally - if you match the two (a type and a required attribute) then you will be required to enter something and have it match the type.
What that means is that adding basic validation is as trivial as adding the word "required" to your HTML. Consider this login form:
<form action="" autocomplete="off">
<label for="username">Username</label>
<input id="username" name="username" required>
<label for="password">Password</label>
<input id="password" name="password" type="password" required>
<p/>
<input type="submit" class="btn" value="Login">
</form>
That's it. No JavaScript library. No form submit handler. Nada. In compliant browsers, you immediately get visual feedback when submitting the form:

The browser actually prevents you from submitting the form. Entering a value for the username and then submitting again automatically moves the error to my password field:

How much simpler can it get? Now let's talk about type validation. HTML5 adds a variety of new input types. Two of them are particularly useful - email and url. These form fields render the exact same as any normal text field, but in terms of validation, they will be a bit more picky about what you enter. We just demonstrated a login form, now let's look at a slightly more complex registration form.
<form action="" autocomplete="off">
<label for="username2">Username</label>
<input id="username2" name="username" required>
<label for="password2">Password</label>
<input id="password2" name="password" type="password" required>
<label for="email">Email</label>
<input id="email" name="email" type="email" required>
<label for="url">Homepage</label>
<input id="url" name="url" type="url">
<p/>
<input type="submit" class="btn" value="Register">
</form>
Notice I've still got a required username and password. I've added an email field that is required (note the use of type="email") and an optional url field. The type is set to url but it is not required.
Just by changing the types and adding required, I've now added logic to my form such that:
- Username and password will be required.
- Email will be required, and it must be a valid email address.
- Homepage is not required, but if I type anything in, it must be a valid URL. (And by valid we mean syntax wise. It could be a valid URL and not actually resolve to a host.)
Want to play with this? Then check out my demo: https://static.raymondcamden.com/demos/2012/mar/16/forms/10_validation.html
But wait! There's more. What if you want to do a more customized validation? I mentioned earlier that we can use JavaScript, and I plan on talking about that more in the next blog entry. But there is also another option: Regular Expressions. You can add simple regex checks to a field by using the pattern attribute. I found a great example of this that adds simple logic to require a minimum size: pattern="[a-zA-Z0-9]{5,}". Here's a modified form of our login and registration form that will require a username and password to be 5 characters long. Usernames are also set to require letters and numbers only.
<h2>Login</h2>
<form action="" autocomplete="off">
<label for="username">Username</label>
<input id="username" name="username" pattern="[a-zA-Z0-9]{5,}" title="Minimum 5 letters or numbers." required>
<!-- Credit: http://stackoverflow.com/questions/5458076/regex-in-new-pattern-attr-for-html5-forms -->
<label for="password">Password</label>
<input id="password" name="password" type="password" pattern=".{5,}" title="Minmimum 5 letters or numbers." required>
<p/>
<input type="submit" class="btn" value="Login">
</form>
<h2>Register</h2>
<form action="" autocomplete="off">
<label for="username2">Username</label>
<input id="username2" name="username" pattern="[a-zA-Z0-9]{5,}" title="Minmimum 5 letters or numbers." required>
<label for="password2">Password</label>
<input id="password2" name="password" type="password" pattern=".{5,}" title="Minmimum 5 letters or numbers." required>
<label for="email">Email</label>
<input id="email" name="email" type="email" required>
<label for="url">Homepage</label>
<input id="url" name="url" type="url">
<p/>
<input type="submit" class="btn" value="Register">
</form>
Note the use of the title attribute to provide a hint to the user. In Chrome and Firefox, this is even rendered in the error:

You can view a demo of this one here: https://static.raymondcamden.com/demos/2012/mar/16/forms/11_validation_regex.html
So - the big question is - what in the heck happens with browsers that don't support this? Nothing. And there's nothing at all wrong with that. Why? First off - when these new form features "fail", they fail well. The user doesn't see anything weird - they just seem forms. Secondly - we all use server-side validation and don't ever assume client side validation is going to work. No one makes that mistake. No one. So that being said - even with easy to use jQuery-based solutions, I can see skipping that and just relying on this. For folks with decent browsers, they get a great feature with about 2 seconds of my time to code it. For folks with crap browsers (hint - rhymes with "my pee"), they still get a usable form and server-side validation.
Archived Comments
heh. You said, "my pee."
huhuhhuhhuhuh.
All of the IE enhancement budget was spent on television advertising.
Interesting! FF correctly rendered the alert tip/box to the correct form field.
Chrome however didn't - then I noticed I had my font size jacked up slightly. Resetting my font size it displayed correctly.
FF seems to handle the font size better but not perfect.
We're getting there but it's still frustrating to see such differences in browsers.
Are they adding any of the HTML5 input validation to cfForm, cfInput, etc in CF10?
We have been a very heavy user of xForms/cfForm. The xForms solution works fantastic 99% of the time and we've customized it a lot, however, when you want to do something 'special' we have to work very hard to make it happen. I have all ready written a replacement set of custom tags that will give us the same experience. Basically wrapping cfinput... but now you are giving me ideas... I digress to my original question....
Why would they? We already support form validation via JS - so that wouldn't be necessary - and you can use html5 types (cfinput type=email) in CF10 so that should work too... although I think it forces the client side validation (I mean in JS). Basically - I would NOT recommend cfform if you want precise control over your forms. (That's my humble opinion.)
Firefox accepts a@b as a valid e-mail. Bad idea.
Interesting that 'url' will accept http://www. as well ... still, very cool to have a first cut that's JS-free. Will definitely be looking at this in more depth for some internal apps.
@Jason: Isn't that technically a url?
@Patrick: So yeah, see what Jason found. It's not going to be perfect. :)
Yyes, I think a URL can end with a '.' according to the spec, so it would technically be valid IF 'www' were a top-level domain. So, format-wise, it might be OK, like the email example @Patrick pointed out.
I played a bit with this. You can easily modify the form using firebug. Remove pattern or required attribute and just submit it w/o validation.
@Patrick: You are correct. If you play a bit you can defeat the validation, but modification via Firebug is possible with any client-side validation mechanism. This is not a vulnerability introduced by the HTML5 form validation features. It's why you always use server-side validation as well. Client side validation is merely a convenience for the user.
@Patrick: What Ben said. ;) Seriously - and I mentioned this somewhere - but client side validation is simply for the user experience. Not for security. You always back it up with server side validation. My feeling is this - look how easy it is to use. To me - that makes it worthwhile even though you need the back up checks.
Hi, great tutorial! Any thoughts on how to achieve a conditional required field? Say you have a field that is required only if a specific checkbox is clicked? How do you do that? One could think about the use of JS, but in that case we would encounter two problems. First, if JS would be disabled, some fields would keep being validated while the conditional fields not. Second, even with the use of JS, how could you present/style the error message box in order to be consistent with the default one? Thanks!
As far as I know, you would have to use JS. As to your two problems:
"First, if JS would be disabled, some fields would keep being validated while the conditional fields not."
To me, and this is just my opinion, it falls into the 'your browser is so sucky it doesnt matter' category, and since we are using server-side validation as a 100% backend, we are safe.
"Second, even with the use of JS, how could you present/style the error message box in order to be consistent with the default one?"
I think you would get around that by using JS to manipulate the DOM. So imagine an email field that does NOT have the required field. If you click on some checkbox for a newsletter, for example, I'd use JS to add the required attribute to the DOM. Then when you submit the form, the UI should be the exact same as everything else.
That's just an idea though - haven't tested it. (But going to since now I'm curious.)
Thanks for your answer. Yeah, that's the way I would go too. I would add the required attribute with JS and add the necessary validations for older browsers that don't support form validation. Also, and to prevent inconsistency when JS is disabled, I would add the formnovalidation attribute to the form and remove this with JavaScript, so that the validation is just done on server side when JS is off.
Oh now that's a smart trick - using formnovalidation and removing it with JavaScript. Thanks for sharing that!
Very useful article and resource. Couple of questions:
a. Html5 Form doesn't need a method=["post"|"get"] so, how does it know what is what?
b. Running the demo, after the username/password/email/etc. have been submitted, they appear in the url bar. Should that happen?
a) It defaults to GET.
b) Yep, because of A. Normally I'd have added method="post".
Okay, thanks. I put the code into a web app with a method="post" and got a "Method Not Allowed" error. Aaah!
That would be something up on your server.
In order to do server-side validation you need to use <cfinput> tags and use the method "validateat=onserver". However <cfinput> does not support HTML5 attributes so it will not let me use the new "required" function. It just renders a normal <input> element without the "required" part.
How would you suggest one can offer HTML5 validation and server-side validation in one application?
"In order to do server-side validation you need to use <cfinput> tags and use the method "validateat=onserver". "
Absolutely not! That's one way of doing it but not the only way. I never recommend cfinput myself.
So to answer your last question, I'd just do the validation manually.
Do you mean by using hidden fields? Using cfparam with multiple if/else statements is very tedious
No, I didn't mean hidden fields - I meant manually, ie, cfparam and CFIFs. I don't find it tedious. It isn't exciting, but it works.
To echo Ray's position: hidden fields are able to be manipulated, so to do server-side validation, you actually have to check when the form is posted. Ray recommends using CFIF and CFPARAM, and that's exactly right: it's done on the form post action. CFIF NOT LEN(form.firstName) THEN errors = "ERROR: You must provide a First Name value." CFIF LEN(errors) THEN return errors ELSE [save to database] and return success
Eh? How is saying "Use CFIF" not right? It is... but obviously is just a high level remark of "use conditions" and not a full code sample. ;)
@Ray, I said CFIF "was exactly right" :)
I was just trying to provide a little pseudo code to back you up, because I completely agree that hidden fields don't address the server-side solution YOU were suggesting ;)
-sigh- It's what I get for reading too quickly and being a bit defensive today (re: the HTML5/Sencha debate). Sorry!
It's all good, Raymond, and thank you (so many times) for all you do for the CF and web development communities!
I just have one question how do you called the pop up window display after the error. How can one possibly code it. If any of you have an idea please let me know.
LeBoss - are you saying you want some form of modal window to pupup for error display?
Yes, something that look exactly like the one above
I have seen it on facebook and many popular websites i just don't have any idea how to make it. If you can help me i will be very grateful.
There are multiple JavaScript libraries out there that do UI things. I'd check out jQuery UI and it's Dialog control.
And what about that stupid IE that does not know what html 5 is ;)
IE isn't a lost cause. IE10 supports form validation: http://caniuse.com/#feat=fo...
... and yet IE10 doesn't work with Sharepoint. Although I think that's more a problem with Sharepoint than with IE10. LOL Microsoft, can't even get their own products to work with each other.
You should trying using some Sharepoint apps on an iPad. That is a level of broken beyond IE stuff. It's so bad instead I just connect to VMware instead.
Believe it or not - I've never used Sharepoint. Ever.
Then go to your CIO and give him a big hug for not forcing that on you.
Oh wait, you work for Adobe these days, don't you? You dodged a bullet there, my friend.
Oh we all have our little issues. For us, it is an internal wiki that requires VPN *and* a OTP. It is super super super secure.
Quick question what is the <p/>
Just a self closing paragraph tag.
yes, good example, but do not forget about some attributes like: novalidate. It can bring much headache like it my case when I wanted to upgrade my blog with HTML5 form validation. Fortunately, I found this article where I read about such things: http://basicuse.net/article.... Such attribute will be useful in case when you need to have cancel or discard button.
Personally I think reset buttons don't serve any purpose - outside of folks accidentally clicking them.