Twitter: raymondcamden


Address: Lafayette, LA, USA

HTML5 Form Validation with Style

03-23-2012 14,637 views HTML5 11 Comments

Welcome to my third and final (although whenever I say that it typically leads to more posts, diversions, and experiments) on HTML5-based form validation. In the first entry I discussed how you could add simple client-side validation to your forms by just using HTML. In my second entry, I demonstrated how to add JavaScript for deeper, and customized validation. In this final entry, I'll discuss how to employ CSS to visually enhance your forms.

While doing research into this topic, I had a vague idea of the CSS styles that could be used. But I had a difficult time finding an exact specification for the feature itself. Called "CSS Pseudo-Classes", these are styles that reflect a state of a DOM item instead of simple tag or class. I came across an excellent article by Ryan Seddon on form validation where he lists the following pseudo-classes:

  • valid
  • invalid
  • required
  • optional
  • in-range
  • out-of-range
  • read-only
  • read-write

Right away, we can see that there are some interesting options here. I went into this research expecting support for invalid and valid, but the other options surprised me. Using in-range and out-of-range, you can actually apply styles to number text fields that are not within a particular range. I also think it is cool that you can combine required, invalid, and valid to visually represent three separate states for a form field. Let's look at an example.

Here is one of the forms I used in my first example. It contains both a login and registration section.

view plain print about
1<h2>Login</h2>
2<form action="" autocomplete="off">
3<label for="username">Username</label>
4<input id="username" name="username" pattern="[a-zA-Z0-9]{5,}" title="Minmimum 5 letters or numbers." required>
5<!-- Credit: http://stackoverflow.com/questions/5458076/regex-in-new-pattern-attr-for-html5-forms -->
6<label for="password">Password</label>
7<input id="password" name="password" type="password" pattern=".{5,}" title="Minmimum 5 letters or numbers." required>
8<p/>
9<input type="submit" class="btn" value="Login">
10</form>
11
12<h2>Register</h2>
13<form action="" autocomplete="off">
14<label for="username2">Username</label>
15<input id="username2" name="username" pattern="[a-zA-Z0-9]{5,}" title="Minmimum 5 letters or numbers." required>
16
17<label for="password2">Password</label>
18<input id="password2" name="password" type="password" pattern=".{5,}" title="Minmimum 5 letters or numbers." required>
19
20<label for="email">Email</label>
21<input id="email" name="email" type="email" required>
22
23<label for="url">Homepage</label>
24<input id="url" name="url" type="url">
25
26<p/>
27<input type="submit" class="btn" value="Register">
28
29</form>

And here's how it renders normally.

Now let's add a bit of CSS:

view plain print about
1<style>
2input:required {
3 border-style:solid;
4 border-width:thick;
5}
6input:valid {
7 background-color: #adff2f;
8}
9input:invalid {
10 background-color: #f08080;
11}
12</style>

I've defined 3 different things here - all using pseudo-classes. The first defines a thick border for required items. The second defines a greenish (it's a color - honest) color for valid items and a reddish color for invalid items. Now look at the same form:

Big difference, right? Now look at it after I've done a bit of editing.

What isn't evident in these screenshots is that Chrome and Firefox both animate these styles. It's a minor animation, pretty subtle, but it works rather well. You can demo this form here:

Just imagine if someone with - you know - actual design sense were to work with this? Now let's look at another example. In the form below, I've got a few simple text fields but also some numeric ones:

view plain print about
1<form id="mainForm">
2
3 <p>
4 Not required, nothing special:
5 <input type="text" id="field0">
6 </p>
7
8 <p>
9 Just required:
10 <input type="text" id="field1" required>
11 </p>
12
13 <p>
14 Email:
15 <input type="email" id="field2" required>
16 </p>
17
18 <p>
19 URL:
20 <input type="url" id="field3" required>
21 </p>
22
23 <p>
24 Number:
25 <input type="number" id="field4" required>
26 </p>
27
28 <p>
29 Number (Min 0):
30 <input type="number" id="field5" required min="0">
31 </p>
32
33 <p>
34 Number (Max 10):
35 <input type="number" id="field6" required max="10">
36 </p>
37
38 <p>
39 Number (Min 1, Max 10):
40 <input type="number" id="field7" required min="1" max="10">
41 </p>
42
43 <p>
44 Number (Min 1, Max 10, Step 2):
45 <input type="number" id="field8" required min="1" max="10" step="2">
46 </p>
47
48</form>

I used the following CSS. Note specifically the in-range and out-of-range pseudo-classes:

view plain print about
1<style>
2input:required {
3 border-style:solid;
4 border-width:thick;
5}
6input:valid {
7 background-color: #adff2f;
8}
9input:invalid {
10 background-color: #f08080;
11}
12input:out-of-range {
13 background-color: #808080;
14}
15input:in-range {
16 background-color: #8a2be2;
17}
18</style>

In Chrome, this is what you get:

My numeric fields are empty, but marked in-range, which is a bit weird. But look what happens when I intentionally enter a bad value for one of them:

As you can see, it did recognize my number was too low and colored it wrong. All very interesting, but it looks like Firefox doesn't support these two at all:

It looks like Firefox isn't supporting the number type at all so it makes sense for the pseudo-class not to be supported either. Thankfully Firefox supports mission critical features like Canvas, which is obviously more much more important than form fields. (Oops, sorry, I started my old rant again. I'll stop.) It does fall back nicely though so it's certainly not a total loss. For an example of that, we can always rely on IE...

You can demo this version below.

Related Blog Entries

11 Comments

These comments will soon be imported into Disqus. To add a comment, use Disqus above.
  • Commented on 03-23-2012 at 11:35 AM
    One wonders if there's a jQuery plugin that handles $('input:number') and styles them appropriately. Maybe jQuery UI. I don't know.
  • Commented on 03-23-2012 at 11:39 AM
    I think everything I've shown in this series could be pollyfilled (faked ;) easily enough. I'm trying to avoid that and just focus on the specs.
  • Commented on 03-23-2012 at 11:43 AM
    Ah. I'm thinking of someone reading carefully down through the entire post, paying attention to every jot or tittle and finally reading in the last paragraph: "It looks like Firefox isn't supporting the number type at all."
  • Mike #
    Commented on 03-23-2012 at 3:56 PM
    HTML 5 rocks,

    unfortunately a lot of corporate customers are still on IE 8 and bellow and validation fails miserably with IE (sometime even 9)

    Thanks
    Mike
  • Commented on 03-23-2012 at 6:01 PM
    Ray, great work as usual. Minor point but there is a typo in your title text. The word minimum is spelled incorrectly as "Minmimum".
  • Commented on 03-24-2012 at 8:27 AM
    @Barry: Thanks, fixed (well in code - going to edit the blog entry in a sec)

    @Mike: But remember - even if every user is using a kick butt browser, you STILL can't rely on this. You must use server-side validation as well. So IE not working isn't a big deal to me. To me, the power here is how easy it is to add the client-side validation.
  • Commented on 07-11-2013 at 10:24 AM
    This is like a fresh of breath air. I have seen so many bad and ugly methods for form validation, has almost given up on trying to find something like this. Great work!
  • Commented on 07-11-2013 at 10:25 AM
    Glad you like it. Web Standards FTW.
  • Ritabrata Kar #
    Commented on 06-25-2014 at 6:01 AM
    i need (add,edit,delete) code in php..................for access that page & change(as admin) my record details.
  • Commented on 06-25-2014 at 8:55 AM
    Then you should write it.
  • David Maggard #
    Commented on 06-25-2014 at 10:28 AM
    He should get on that.