Adding HTML5 placeholder attribute support through progressive enhancement
I continually talk about HTML5 and how progressive enhancement is a simple approach to make any new behavior possible in web browsers that haven’t implemented it yet. I thought I’d show you a simple example how to do this with the new placeholder
attribute for input
elements.
Introducing the placeholder attribute
The placeholder
attribute is there to show the user a text, a hint of sorts, but as soon as the text field gets focus, you want that value to be cleared. All the HTML5 code it takes is:
<input type="text" id="search-text" placeholder="Enter terms here">
However, the status of implementation right now is that only WebKit-based web browsers (Google Chrome and Safari) support this. So, what do we do for older web browsers?
For web browsers not supporting the placeholder attribute
There are two things we need to add to get this in web browsers not supporting it:
- A certain class to display our created placeholder in a semi-disabled fashion
- A JavaScript snippet to simulate the placeholder attribute behavior
CSS
<style> .placeholder { color: #aaa; } </style>
JavaScript
This JavaScript is based on using jQuery for class adding/removing and event handling, but naturally you could use just about any JavaScript library or just write it yourself. Just keeping it short and simple here, ok? 🙂
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> <script> // To detect native support for the HTML5 placeholder attribute var fakeInput = document.createElement("input"), placeHolderSupport = ("placeholder" in fakeInput), clearValue = function () { if (searchField.val() === originalText) { searchField.val(""); } }; // Applies placeholder attribute behavior in web browsers that don't support it if (!placeHolderSupport && confirm("Yeah?")) { var searchField = $("#search-text"), originalText = searchField.attr("placeholder"); searchField.val(originalText); searchField.addClass("placeholder"); searchField.bind("focus", function () { searchField.removeClass("placeholder"); clearValue(); }); searchField.bind("blur", function () { if (searchField.val().length === 0) { searchField.val(originalText); searchField.addClass("placeholder"); } }); // Empties the placeholder text at form submit if it hasn't changed searchField.parents("form").bind("submit", function () { clearValue(); }); // Clear at window reload to avoid it stored in autocomplete $(window).bind("unload", function () { clearValue(); }); } </script>
Progressive enhancement
This is an easy example of progressive enhancement: first check for native support, and if it’s not there, implement the same behavior through JavaScript (if JavaScript is available, of course).
Happy scripting!
Nice! But i'd call it total enhancement since it's enhancing the browsers not supporting the placeholder attribute to 😛
I spot a few possible optimizations…
<code>
// To detect native support for the HTML5 placeholder attribute
var fakeInput = document.createElement("input"),
placeHolderSupport = ("placeholder" in fakeInput);
</code>
Could be written as:
<code>
// To detect native support for the HTML5 placeholder attribute
var placeHolderSupport = ('placeholder' in document.createElement('input'));
</code>
Better yet, don’t use the <code>placeHolderSupport</code> (should really be <code>placeholderSupport</code> btw) variable and just put the above code inside the <code>if</code> check.
<code>var searchField = $("#search-text"),
originalText = $("#search-text").attr("placeholder");
</code>
This queries the DOM twice looking for an element with the ID <code>search-text</code>. Please don’t even do that. Since you’re storing a reference to the jQuery object for that element anyway, why not reuse that?
<code>var searchField = $("#search-text"),
originalText = searchField.attr("placeholder");
</code>
The following looks a bit silly:
<code>if (searchField.val().length === 0) {}</code>
You can just use this instead:
<code>if (!searchField.val().length) {}</code>
Your code will not work for more than one element. It would probably be an even better example when written as a generic jQuery plugin.
Of course, this is something that has already been done several times.
Having said that, great article! Good to see you raising awareness for the HTML5 placeholder attribute.
Johan,
Well, to me it's progressive, but I can live with that name too. 🙂
Mathias,
About support check and those variables, it could definitely be made shorter. Same goes for just one element as opposed to having a loop and find every element with a certain class.
But, bear in mind that this is as much as teaching someone about it and making that line of thinking as clear as possible, and not just about offering a solution to include and be done.
What I definitely do agree about, though, is the check for the placeholder attribute value when that element has already been found, and I've updated the code for that.
And, good work putting together plugins for people. 🙂
You can also use jQuery's support object to store informations about browser features:
$.support.placeHolder instead of placeHolderSupport
I think your example is a misuse of the placeholder attribute, cause it should give the user a hint how the input data should look like (see the spec). What you got here is a label. As you remove the value at focus the value will never be read by a screenreader so its not a real progressive enhancement. Btw. I'm not sure how screenreader will handle the placeholder.
alexander,
Good point!
Andreas,
I agree, my example wasn't all clear, and it should have been more hint-y. I think in regards to the placeholder attribute, the support isn't really there yet in screen readers.
But if I'm not mistaken, screen readers should at least be able to read the value of a text field before it actually gains focus, right? And maybe it's something we can use WAI-ARIA Live for alerting them on the change at focus?
It should probably check to see if the searchfield's value attr was already set in the HTML, no? 🙂
…and remove the placeholder text on form submit, thinking about it 😉
sil,
Yes, and yes. 🙂
But for that, I refer to other people's complete solutions for every scenario and not this code that is here for inspiring. 🙂
Ha! You beat me to it with this article.
May I suggest not interfering with the val attribute though, as that means it is submitted with the form. Perhaps text overlaid on the input would be better?
Robert: what, like http://www.kryogenix.org/code/browser/labelify/ ? 🙂 Although it uses label rather than placeholder because placeholder didn't exist two years ago when I wrote it 😉
Oh Robert….there's a nasty bug in the code 🙁
I wrote a "hint" jQuery plugin a long while back, but also I've also ported this to support placeholder (as you've done too) via a gist.
So what's the really big bug? What happens if the form is submitted without the field being focused? … I know you'll spot it 😉
i made a ready to use plugin out of it, including some improvements:
http://gist.github.com/442875
[…] durch Robert´s Post/Script zu “Adding HTML5 placeholder attribute support through progressive enhancement” und vor allen Dingen einigen Kommentaren habe ich mein eigenes HTML5 Placeholder-Script […]
Joe, Remy,
I understand the problem, and I have added code that clears the mimicked placeholder text before submit, if it hasn't changed.
sil,
Absolutely, it's pretty much the same thing. 🙂
Remy,
Thanks for the suggestions!
alexander,
Great, thanks!
I'd like to remind you to always set a background along with any color you set on form elements, and vice versa.
I'm a user of dark desktop themes and form elements use that dark style, so I regularly end up with dark text on dark backgrounds, having to use Firebug and userstyles to rectify these problems. A serious usability issue.
So set both color and background, or leave it to its default.
Kenneth,
Good input!
Quite an elegant solution )
I looked at jQuery plugins for placeholder the other day, and there's one thing that many of them, and your code is missing. How do you handle password inputs? The placeholder should show the text for password fields, but your code shows them as stars. Since the type attribute can't be changed on password fields, you need to construct a separate field and replace the password one.
Tricky, and annoying.
c69,
Thanks!
Emil,
Good point! Either that replacement approach is one way to go, or perhaps using an absolutely positioned label element or so. Neither solution is a nice one, though.
Maybe someone will find this jquery plugin useful. Please leave me any comments or ideas.
http://www.andresvidal.com/labs/placeholder.html
Andres,
Thanks for the tip!
[…] instance, the placeholder attribute is just wonderful on forms. And here’s a way to provide progressive enhancement through jQuery to browsers which don’t support this […]
Does the unload function actually fulfill its stated purpose? It doesn’t seem to make a difference in IE7-9 and Firefox 2-3.6. IE doesn’t store the values for autocomplete, while Firefox does, both regardless of whether the unload listener is present or not.
However, the unload function does keep the browser from leaving the text in the field when the page is reloaded. Though for it to do that in IE, beforeunload needs to be used instead, which works in Firefox as well.
Kravimir,
Haven’t tried it in a long time, but if you need to tweak the script to make it work better for you, feel free!