colinramsay.co.uk

Simple Javascript Watermarks in Input Fields

17 Oct 2007

I had a change request today to label a couple of text input fields with a watermark. The client didn't think it was immediately obvious what the user was supposed to enter, but we didn't have space for the traditional text labels next to the inputs. The suggested solution was to have a watermark which "underlayed" the input box with the label text which disappears on focus and reappears on blur.

Smoke & Mirrors

The trouble was that these boxes appeared in various places in the site, and I had a load of issues to address. Since we'd decided that this was more of a prompt than a necessity, I didn't feel too bad in using javascript to hook up this fix, and when I realised all of these fields had a particular CSS class, "name", on the surrounding containing element, I was good to go with a quick trick. All of the big javascript libraries have a helper to select elements by class; in Prototype it's the $$ utility method. Using this, I could grab all of the elements I wanted, and perform an action:

$$('.name').each(function(element) {
	// do something with element
});

$$ grabs me the elements by selector, in this case ".name", all of the elements marked with a class of "name". It returns them as a Prototype array, which I can iterate over using the Array.each method. Each takes an anonymous function with a single parameter: an array item, and in our case that'll be an element which matches our selector. I now needed to do something with this element, so I define a new function to set the watermark:

function setWatermark(element) {
	if(element.value.length == 0) {
		element.style.background = 'white url(/content/images/watermark.png) no-repeat top left;';
	}
}

A Swirl of the Cape

We can use this function in our main code to initialise the watermark. We then create event handlers for the focus and blur events, where setWatermark will handle focus, and blur will simply clear the background image.

$$('.name').each(function(element) {
	// initialise
	setWatermark(element);

	Event.observe(element, 'focus', function() { setWatermark(element); });
	Event.observe(element, 'blur', function() { element.style.background = ''; });
});

That's it! Wrap it all up in a window.load (or equivalent) and you're ready to go. This is a great example of unobtrusive javascript and progressive enhancement.

At the End of the Day

I've truncated this code for example purposes. The real version is packaged up using the YUI Blog Module pattern, and allows alternate image paths to be passed to the setWatermark function. If you'd like to see this in action, I've uploaded an example watermark page, it's only tested in Firefox and IE6 but should work in IE7 too. I know it's got issues in Opera 9.5. Enjoy!