TL;DR Replace your JS validation with HTML5 validation. It's easier than you think and gives you a ton of markup/styling control.
So you need to validate a form. You do the right thing and start with server-side validation. Then, if you're a good web-designer, you want to add in some client side validation so your users get feedback on whether they filled out the form correctly or not. If you're a really good web-designer you might even make that feedback instantaneous so the user is made aware that they entered a valid email address as soon as it becomes a valid email address.
You reach for your favorite jQuery library. You might even be cool enough to use a vanilla JavaScript library.
You add some extra markup. Re-style some stuff... Add some JavaScript validation rules. Connect the JS to the server via AJAX. Bash your head against the keyboard a few times because you haven't done this in a couple months and have to look up exactly how that new JS validation library does things... etc.
You get the picture. It's not fun.
What if you could skip all that JS stuff and just validate with HTML5 attribute validators and CSS?
Basically you add attributes like required
or type="email"
to <input>
fields and your browser does the rest.
Go ahead and try to submit the form in this CodePen demo with no content. Then try to submit it without a valid email address.
You may have noticed you can enter an email like a@a
. Clearly you want a real e-mail address. Let's make sure it matches the pattern of having a dot and 2 or 3 characters on the end. We can do this using the pattern
attribute and regex.
If you're tentative about learning regex you need to get over it. Regex is insanely powerful and in every type of programming you'll ever do. Regex101 is a great site for learning/testing/sharing patterns, and the fine folks at #regex on Freenode are incredibly helpful.
I suck at complicated regex so I'll Google for "email regex" (since I'm sure this has been solved already) and ended up finding one on regular-expressions.info. Here's our regex. If you read a little about the pattern you'll realize the author excluded lowercase matches because they expect you to use a case-insensitive flag. HTML5 input patterns don't accept flags so to get lowercase letters we need to add the uppercase and lowercase range (e.g. A-Za-z
). You can read exactly what each part of the pattern is doing in the right panel.
To make our validation errors throw something other than "Wrong format!" we can specify a title
attribute with a validation error.
Now try the email input in this demo.
Don't worry, you won't have to write crazy patterns for every input you have. Most of the time you just want to require something and make sure it's a certain type of data. For instance, a number over 5 might look like <input type="number" min="5" required>
.
Keep in mind that not all browsers support all the various validation attributes. For instance, FireFox doesn't support minlength
. pattern
has pretty good support though so you can always replicate functionality. minlength
can be replicated with pattern=".{3,}"
where 3
is however long it needs to be.
If you can't find a pattern you had access to in your old JS library, you can probably find it by browsing their source code since ultimately the JS library is simply matching the exact same regex patterns as we are.
Wouldn't it be nice if our input would display some sort of indication when it was valid? There's a :valid
CSS selector for that. There's also an :invalid
selector. Check out the demo.
You'll notice the obvious caveat that invalid styles are showing up even when we haven't touched the input.
You might think about doing something like :invalid:not(:empty)
but it won't work because browsers are stupid and always consider form elements empty.
We could do some trickery with the new :placeholder-shown
pseudo-selector as shown in this demo, but browser support for :placeholder-shown
is horrible and there isn't a modern polyfill for it yet. Bummer.
For now our best bet is to simply add some JavaScript to toggle a class depending on if the input is empty or not. Here's the working demo.
My favorite part about this approach is you have complete CSS control over every bit of your form.
By pushing the <span>
under the <input>
we gain access to the adjacent sibling selector on our .empty
class and can create a faux placeholder that beautifully slides out of the way as soon as the input is no longer empty. Here's an example.
If the <span>
being under the <input>
offends your sensibilities or isn't accessible enough, you can always tweak the JavaScript to add the empty
class to the <label>
instead. Then it's just a matter of tweaking the CSS a bit. Here's an example doing it that way.
The validation classes also work on the <form>
element so you can really go nuts with style control.
There's no limit to what you can do with this approach. Some ideas:
- Add validation icons that fade in/out.
- Shake the input if the user unfocuses and it is invalid.
- Dim inputs as they're filled out correctly.
- Perfect in modern browsers and IE10+.
- IE9- doesn't support validaton pseudo selectors so you won't get the styling but the form still functions very nicely.
There's no way to style the validation messages. Browsers disabled the ability to style those. I don't necessarily think this is a bad thing since people will be used to these validation styles. In fact, that's probably why browsers decided to axe our access to them. Now they are standardized.
They're also out of the flow of the page so you don't have to worry about them pushing form elements around with their appearance.
If you absolutely need complete control over validation styles, this method might not be for you.
I'm excited to get some feedback on this and would love to see some cool validation styles/techniques.
Danny King's "Adaptive Placeholders" blog post got me thinking about this.