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!

25 Comments

  • Johan says:

    Nice! But i'd call it total enhancement since it's enhancing the browsers not supporting the placeholder attribute to :P

  • Mathias says:

    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.

  • Robert Nyman says:

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

  • alexander farkas says:

    You can also use jQuery's support object to store informations about browser features:

    $.support.placeHolder instead of placeHolderSupport

  • Andreas says:

    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.

  • Robert Nyman says:

    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?

  • sil says:

    It should probably check to see if the searchfield's value attr was already set in the HTML, no? :)

  • sil says:

    …and remove the placeholder text on form submit, thinking about it ;)

  • Robert Nyman says:

    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?

  • sil says:

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

  • Remy Sharp says:

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

  • alexander farkas says:

    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 […]

  • Robert Nyman says:

    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.

  • Robert Nyman says:

    Kenneth,

    Good input!

  • c69 says:

    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.

  • Robert Nyman says:

    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.

  • Andres says:

    Maybe someone will find this jquery plugin useful. Please leave me any comments or ideas.

    http://www.andresvidal.com/labs/placeholder.html

  • Robert Nyman says:

    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 […]

  • Kravimir says:

    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.

  • Robert Nyman says:

    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!

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>