A look at HTML5 Form Validation

This post is more than 2 years old.

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.

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA https://www.raymondcamden.com

Archived Comments

Comment 1 by Doug posted on 3/16/2012 at 9:36 PM

heh. You said, "my pee."

huhuhhuhhuhuh.

Comment 2 by Chuck S posted on 3/16/2012 at 10:55 PM

All of the IE enhancement budget was spent on television advertising.

Comment 3 by Jim Priest posted on 3/16/2012 at 10:58 PM

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.

Comment 4 by Justin Hansen posted on 3/17/2012 at 12:02 AM

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

Comment 5 by Raymond Camden posted on 3/17/2012 at 12:46 AM

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

Comment 6 by Patrick Heppler posted on 3/17/2012 at 2:45 AM

Firefox accepts a@b as a valid e-mail. Bad idea.

Comment 7 by Jason Fisher posted on 3/17/2012 at 5:03 PM

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.

Comment 8 by Raymond Camden posted on 3/17/2012 at 7:26 PM

@Jason: Isn't that technically a url?
@Patrick: So yeah, see what Jason found. It's not going to be perfect. :)

Comment 9 by Jason Fisher posted on 3/18/2012 at 2:48 AM

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.

Comment 10 by Patrick Heppler posted on 3/29/2012 at 11:26 AM

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.

Comment 11 by Ben Burwick posted on 3/29/2012 at 6:01 PM

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

Comment 12 by Raymond Camden posted on 3/30/2012 at 3:33 PM

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

Comment 13 by Jonas posted on 4/16/2012 at 8:17 PM

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!

Comment 14 by Raymond Camden posted on 4/16/2012 at 8:25 PM

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

Comment 15 by Jonas posted on 4/16/2012 at 8:40 PM

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.

Comment 16 by Raymond Camden posted on 4/16/2012 at 8:45 PM

Oh now that's a smart trick - using formnovalidation and removing it with JavaScript. Thanks for sharing that!

Comment 17 by dbv posted on 11/30/2012 at 1:25 AM

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?

Comment 18 by Raymond Camden posted on 11/30/2012 at 1:33 AM

a) It defaults to GET.
b) Yep, because of A. Normally I'd have added method="post".

Comment 19 by dbv posted on 11/30/2012 at 2:04 AM

Okay, thanks. I put the code into a web app with a method="post" and got a "Method Not Allowed" error. Aaah!

Comment 20 by Raymond Camden posted on 11/30/2012 at 3:54 AM

That would be something up on your server.

Comment 21 by Token posted on 12/16/2012 at 6:09 AM

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?

Comment 22 by Raymond Camden posted on 12/16/2012 at 7:49 AM

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

Comment 23 by token posted on 12/16/2012 at 8:03 PM

Do you mean by using hidden fields? Using cfparam with multiple if/else statements is very tedious

Comment 24 by Raymond Camden posted on 12/17/2012 at 8:04 AM

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.

Comment 25 by Jason Fisher posted on 12/18/2012 at 12:40 AM

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

Comment 26 by Raymond Camden posted on 12/18/2012 at 12:45 AM

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

Comment 27 by Jason Fisher posted on 12/18/2012 at 12:50 AM

@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 ;)

Comment 28 by Raymond Camden posted on 12/18/2012 at 12:52 AM

-sigh- It's what I get for reading too quickly and being a bit defensive today (re: the HTML5/Sencha debate). Sorry!

Comment 29 by Jason Fisher posted on 12/18/2012 at 12:54 AM

It's all good, Raymond, and thank you (so many times) for all you do for the CF and web development communities!

Comment 30 by LeBoss posted on 2/9/2013 at 1:03 AM

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.

Comment 31 by Raymond Camden posted on 2/9/2013 at 1:07 AM

LeBoss - are you saying you want some form of modal window to pupup for error display?

Comment 32 by LeBoss posted on 2/9/2013 at 1:17 AM

Yes, something that look exactly like the one above

Comment 33 by LeBoss posted on 2/9/2013 at 1:20 AM

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.

Comment 34 by Raymond Camden posted on 2/13/2013 at 5:51 PM

There are multiple JavaScript libraries out there that do UI things. I'd check out jQuery UI and it's Dialog control.

Comment 35 by Julien posted on 6/14/2013 at 9:58 AM

And what about that stupid IE that does not know what html 5 is ;)

Comment 36 by Raymond Camden posted on 6/14/2013 at 3:24 PM

IE isn't a lost cause. IE10 supports form validation: http://caniuse.com/#feat=fo...

Comment 37 by Doug posted on 6/14/2013 at 3:52 PM

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

Comment 38 by Raymond Camden posted on 6/14/2013 at 4:07 PM

Believe it or not - I've never used Sharepoint. Ever.

Comment 39 by doug posted on 6/14/2013 at 4:44 PM

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.

Comment 40 by Raymond Camden posted on 6/14/2013 at 5:15 PM

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.

Comment 41 by James Polland posted on 5/20/2014 at 8:37 PM

Quick question what is the <p/>

Comment 42 by Raymond Camden posted on 5/20/2014 at 11:20 PM

Just a self closing paragraph tag.

Comment 43 by Heald Price posted on 8/12/2014 at 1:04 AM

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.

Comment 44 by Raymond Camden posted on 8/12/2014 at 1:05 AM

Personally I think reset buttons don't serve any purpose - outside of folks accidentally clicking them.