This is what I’m thinking is the best current way to progressively enhance forms. That is, use HTML5 features when they are available and fall back to JavaScript alternatives when they are not.
Yepnope.js
Load up<script src="scripts/yepnope.js"></script>
Yepnope is a “script loader” which will load scripts conditionally. You give it some kind of boolean value (true or false), if it’s true, it’ll load one set of scripts (or css), if it’s false, a different set. Where do we get that boolean value? From testing a feature with…
Modernizr
Load up<script src="scripts/modernizr.js"></script>
Modernizr gives you the ability to test for HTML5 and CSS31 features. For example, with Modernizr loaded, Modernizr.inputtypes.date
will be true if you are in a browser that supports inputs with a type of date property (Only Opera, since about version 9) and false if you are in a browser that doesn’t support the date type.
Even better: You can get a custom build of Modernizr with only the tests you need (input types and input attributes) with Yepnope also built in in the Modernizr 2 beta builder.
Combine the two
With both of these awesome tools ready to go, we can combine their powers:
yepnope({
test : Modernizr.inputtypes.date,
nope : [
// load scripts to simulate date type
]
});
We don’t need a “yep” in this case, because “yep” means the browser supports it so we don’t need any help.
What do we need for a fallback?
Since we’ve been using the HTML5 input type date as an example, let’s think about a fallback for that. jQuery UI has a pretty sweet datepicker. jQuery is likely to help us solve a lot of fallback problems, so that’s going to be a solid choice. To make the date fallback work, we’ll need to load four resources:
- jQuery
- jQuery UI
- jQuery UI’s CSS
- Our own script calling the datepicker
Load ’em up
With our Yepnope/Modernizr combo, that laundry list looks like:
yepnope({
test : Modernizr.inputtypes && Modernizr.inputtypes.date,
nope : [
'scripts/jquery.js',
'scripts/jquery-ui.js',
'css/jquery-ui.css',
'scripts/datepicker.js'
]
});
Our custom script (loaded last, courtesy of Yepnope) is probably as simple as just calling the datepicker function as soon as possible:
// DOM ready function because we should probably
// be doing this in the <head>
$(function() {
$("input[type='date']").datepicker();
});
And now we get:
![]() |
Opera 11Native support, no extra scripts loaded |
![]() |
Firefox 4No native support, jQuery UI datepicker used. |
Keep it going
Date type support isn’t the only thing we can do here. Let’s say we want to use placeholder as well. Rock’n’roll, just use another yepnope test:
yepnope({
test : Modernizr.input.placeholder,
nope : [
'scripts/jquery.js',
'scripts/placeholder.js'
]
});
Notice we are using jQuery again, and thus specifying the jQuery library script. Let’s say we are in a browser without support for either date or placeholder and we plan to use jQuery for both fallbacks. To do this the best way, we’ll combine the tests the require jQuery into it’s own yepnope block, so we don’t end up loading jQuery more than once.
yepnope([
{
test: Modernizr.input.placeholder || (Modernizr.inputtypes && Modernizr.inputtypes.date),
nope: 'jquery.js'
},
{
test : Modernizr.inputtypes && Modernizr.inputtypes.date,
nope : [
'scripts/jquery-ui.js',
'css/jquery-ui.css',
'scripts/datepicker.js'
]},
{
test : Modernizr.input.placeholder,
nope : 'scripts/placeholder.js'
}
]);
Cooler Than Polyfills
Polyfills are in the same spirit as this. They test for feature support and use native technology if possible otherwise fake it somehow. They are awesome. This is different than polyfills because we don’t need to do the testing, we’ve already done that with Modernizr. So the scripts we load can just assume that there is no support and go from there. I think this might be better than polyfilling because:
- We only load two scripts at first. If a browser is super modern, that’s all it will ever load. With polyfill scripts you load one for every feature.
- We are outsourcing feature detection to Modernizr, which is a project totally dedicated to doing that in the best ways possible. Polyfill scripts might not be as well maintained in that regard.
Or…
I haven’t played with them much, but there are a couple of projects that aim to polyfill every single feature of HTML5 forms. One of them is webforms2. I kinda like the control of doing the feature testing and fallbacks myself, but there is certainly appeal to a set-it-and-forget-it approach.
1 Modernizr tests for other fancy web things that aren’t techically HTML5 or CSS3 but are typically grouped with them, like @font-face.
Actually you don`t need Yepnope + Modernizr, you can just use Modernizr with Yepnope included in it from here http://modernizr.github.com/Modernizr/2.0-beta/ check the other section (Modernizr.load)
Damn you beat me to it lol
Hi, this was very helpful, thank you. Since it’s been 3 years, and things move fast, was wondering if you have an update to this post.
Came to the site to look up some form styling stuff and this was your most recent post – Chris, your a mind-reader!
Hey you can customize your Modernizr download to ship with yepnope http://modernizr.github.com/Modernizr/2.0-beta/ don’t ya know :)
If I get 10 replies on this comment, I’ll donate $150 to Japan’s charity program. :)
1
2
God bless you :)
3
4 – well done!
5 – do it! :D
This is a reply to your comment so you can donate money to Japan’s charity program. Thank you for your kindness.
I think you should do it regardless of comment replies.
9
And 10. Now I feel like I helped a little bit : )
Ooops :D I forgot to add a zero to that number. I wanted to say $1500 :D
@Chris: Well, now are more than 10 people involved in this, it makes me and them feel better about this :)
You wanna add more to that?
For Japan I’ll say Hi. Long time reader never a poster. Love CSS-Tricks And hope your good on that Adel.
Cheers.
I was writing a date picker today (I’ll release it when I finish ;) and I faced this dilemma as well. Opera has a pretty decent native date picker, albeit ugly. However, Webkit just shows a lame spinner-like type of control which is definitely not user friendly. However, there’s no way to safely detect whether the date picker the browser implements is decent or just a way for them to say “we implement the date control too”, without actually providing value to authors.
So, in my case, I chose to use the JavaScript one and fall back to whatever the native control is when JS is not available. I’m not happy that I had to do it, but thanks to @#*&^% Webkit, I think it’s the only way to go. :(
Please do release it! Date-pickers have always had an intense hatred of me and at this point the feeling is mutual.
Cheers.
The really annoying thing is that Webkit browsers report support for the date/time input types but their implementation is completely broken. As Lea points out the control itself is pretty lame but what’s worse is that the user has to type in a value in the correct (machine readable) format or the browser will refuse to submit the form while offering no feedback at all!
I hate to say it, but it’s kind of back to browser sniffing – anything bar Opera needs the JS date picker.
Modernizr reports the current webkit <input type=date> as unsupported. And I’ve gotten confirmation from the webkit engineer behind it that he will not add input validation (which will cause Modernizr to pass) until the UI is in place.
http://formalize.me/
?
… handles how forms look, not function. (it’s super nice though, at the looks stuff)
hum the right panel of this site on this page is screwed up to the bottom
– on topic :) I’m with Gabri
Hi,
pretty good, but selected value should be blocked in field. This way we’ll protect correct value.
It’d be great if every article would mention which exactly browsers support this type (or another) of customization.
But it is good article, anyway. Thanks.
This is something interesting but i have 2 questions:
1) Let’s say that Im using a CMS like Typo3 and I add an extension that includes jQuery (undertermined version, could be older, could be newer).
When yepnode tries to load for the first time the jQuery library, will it detect that one was already loaded, or will it load it again?
2) Is it possible with this method to implement clever HTML5boilerplate?
[[ lines 54-56 from index.html in http://html5boilerplate.com/ ]]
If you are loading jQuery anyway, you don’t need to load it with yepnope for a fallback, just remove that from the array of files to load in the “nope”. I don’t think yepnope will detect scripts loaded that it didn’t load itself.
Chris Coyier is Andy McKee is Chris Coyier
http://onemansblog.com/wp-content/uploads/2008/12/andy-mckee.jpg
haha. I have thought the same thing. I wonder which name is the alias and which name is real.
Had never heard of yepnope. Beginning to use modernizr for css bits, but this combo is really slick.
Don’t really understand what these codes really mean, but I’m beginning to catch some.. Thanks for the tips.
For initializing the datepicker, I would recommend this:
This safeguards against any wonkiness / lag that might occur during the script loading. Since your script loading is deferred, it’s entirely possible that jQueries doc ready could fire before
datepicker.js
is loaded. This protects against that by registering the doc ready function in a callback tied to the loading ofdatepicker.js
.Also, we’ve gotten multiple requests pertaining to not loading the same script twice. This is indeed a valid use case that we’ll likely pick up in future releases.
Thanks for the awesome article.
Really smart stuff, Chris. Thanks.
Every web developer should know about the Progressive enhancement and Ari technology, there are developers still make Old school mark ups and i suggest they should read this
Now that you mentioned a placeholder fallback script / polyfill without actually linking to an example, allow me to promote my jQuery placeholder plugin :)
Theoretically if people use this they could (and maybe should) remove the if/else isSupported stuff at the top, because that’s the point of doing the Modernizr testing first, this script won’t need to do it’s own testing.
BUT, I don’t think Modernizr does individual testing on textarea and input, and I know you know there are some browser discrepancies there (Opera 11 and Safari 4 support it on inputs but not textareas).
So many gotchas with this stuff.
In some browsers, the code in this article will not work. That is because Modernizr only reports items that exist, all others are undefined. Therefore in browsers that support no HTML5 input types you get an error:
To fix this add a guard condition:
I’ve been trying to find out how inputtypes could be defined but don’t see a reason. If you have more details or a test case I’d love to get it.
too much work. i’d rather just use the lowest common-denominator instead of doing double work and increasing the maintenance.
I just built the datepicker fallback but I’m crashing into one nasty issue!
Opera with HTML5 support formats the date as yyyy-mm-dd, while I need this format to be dd/mm/yyyy.
Is it possible to adjust the format with HTML5, or should I build a JS fix on top of this?
YYYY-MM-DD is the ISO 8601 format. You’ll need to convert it to DD/MM/YYYY on your own. I would recommend doing it server-side if possible, but client-side just before sending the data could work.
Good stuff!!! HTML5 are going to be wicket!!
Implementing simply a datepicker on top type=date won’t work, because:
1. HTML5 datepicker format is always yyyy-mm-dd
2. the type=date has several features like min/max, step, valueAsNumber, valueAsDate which needs to be used for configuring the datepicker-polyfill + you have to respect dynamic changes to these properties.
@Jeroen
You have to “fix” this. The simplest way is to make the datepicker always use yyyy-mm-dd.
If you need another (localized) format, you have to do this with javascript. But you cannot add this to the date-type, this type has always sent yyyy-mm-dd. If you don’t do this: newer webkit (Chrome 10+) won’t submit your form. You have to hide the input[type=date], create a new input[type=text] add the datepicker to this new input and then sync the two input-elements using the right format.
Actually, I already have written a polyfill, which shows a localized view (default = locale of the useragent, but can be configured) and sends always correct HTML5 specified data to the server. You can find this @http://afarkas.github.com/webshim/demos/index.html .
This said, if you want to have something similiar, to the thing HTML5 does, the tutorial here is Ok, but if you need something, that implements the right code you should use something like webshims lib. From my testing webshims lib has currently the only working forms-polyfill, which implements the new webforms stuff properly (-> accurate, according to the specification)
regards
alex
(Disclosure: I’m the creator of webshims lib…)
Thanks for the informative article. I’ve been using Modernizr, but hadn’t come across yepnope.js before.
On another note, I came across a verbatim copy of this article on another site and wanted to alert you to that, in case it’s an unauthorized copy.
The site in question is:
www_phphosts_org/2011/03/progressively-enhancing-html5%C2%A0forms/ (replace underscores with dots – I don’t want to link to them).
ever since i started on my web design journey forms have been a sore spot but with your cool teachings and html5 i am loving it! thanks chris! you are the real McCoyier! :)
I have recently been doing alot of work with HTML forms for my PHP. It will be interesting to see how I can integrate this new technique to my forms.