Auto-populating input fields with Prototype
Yesterday I wrote a simple class which auto-populates input fields, and thought it worth sharing. I was originally inspired to write this code by Roger Johansson's post titled Autopopulating text input fields with JavaScript. While I approached the problem from a slightly different angle, I made sure to avoid the pitfalls Roger mentions.
Update —
I've written an update to this article for those interested in auto-populating input fields with MooTools.
Contents
Behaviour
- Placeholder text should be inserted into input field upon page load.
- Placeholder text should be targetable via CSS.
- Clicking or tabbing into input field should remove placeholder text.
- Placeholder text should be reinserted if input field is empty when it loses focus.
HTML5 placeholder text
HTML5 allows placeholder text to be specified in the markup through the
placeholder attribute. In supporting browsers (currently Chrome and Safari)
this produces the behaviour described above with no reliance on JavaScript.
Markup
<input type="search" id="s" name="s" placeholder="search..." />
Styling
input.placeholder { color: #a9a9a9 !important; }
I decided to use #a9a9a9 as Safari uses this colour for placeholder text.
Placeholder class
var Placeholder = Class.create({ initialize: function (element) { this.element = element; this.placeholder = element.readAttribute('placeholder'); this.blur(); Event.observe(this.element, 'focus', this.focus.bindAsEventListener(this)); Event.observe(this.element, 'blur', this.blur.bindAsEventListener(this)); }, focus: function () { if (this.element.hasClassName('placeholder')) this.element.clear().removeClassName('placeholder'); }, blur: function () { if (this.element.value === '') this.element.addClassName('placeholder').value = this.placeholder; } });
The Placeholder class requires Prototype.
Usage
To create a new instance of the Placeholder class, simply pass the constructor a Prototype extended element:
new Placeholder($('s'));
Ensure that the DOM is ready by wrapping everything in Prototype's dom:loaded
event listener. This also avoids polluting the global namespace.
document.observe('dom:loaded', function () { var Placeholder = Class.create({ ... }); $$('input[placeholder]').each(function (input) { new Placeholder(input); }); });
Update —
I've updated the selector used in the above example. Selecting all inputs with placeholder attributes is far more elegant than listing each input explicitly. It also means that an input added anywhere on the site will automatically receive this special treatment (provided that it has a placeholder attribute).
This site's search field shows the code in action.
Update —
For those that would like placeholder text in password input fields not to appear as dots or asterisks in older browsers, I've written an alternative snippet. I drew inspiration from a post on iPhone-like password fields using jQuery.
// provide input hints document.observe('dom:loaded', function () { var PLACEHOLDER_SUFFIX = '_placeholder'; // used for password inputs $$('input[placeholder]').each(function (input) { var label, placeholder, placeholder_text = input.readAttribute('placeholder'); if (input.readAttribute('type') == 'password') { placeholder = input.clone(); placeholder.type = 'text'; // not "password" placeholder.value = placeholder_text; placeholder.addClassName('placeholder'); if (input.id) { // update input id and label placeholder.id += PLACEHOLDER_SUFFIX; label = $$('label[for="' + input.id + '"]') label.invoke('writeAttribute', 'for', input.id + PLACEHOLDER_SUFFIX); } input.writeAttribute({ 'accesskey': '', 'tabindex': '' }); input.hide().insert({ 'before': placeholder }); // when placeholder input gains focus, // hide it and show "real" password input Event.observe(placeholder, 'focus', function () { this.hide(); input.show(); Form.Element.focus(input); }); // when "real" password input loses focus, // if it's empty, hide it and show placeholder input Event.observe(input, 'blur', function () { if (this.value === '') { this.hide(); placeholder.show(); } }); } else { // insert placeholder text input.addClassName('placeholder').value = placeholder_text; Event.observe(input, 'focus', function () { if (this.hasClassName('placeholder')) { this.clear().removeClassName('placeholder'); } }); Event.observe(input, 'blur', function () { if (this.value === '') { this.addClassName('placeholder').value = placeholder_text; } }); } }); });
Possibly related posts
- Auto-populating input fields with MooTools
- wmd ftw!
- Prototype and script.aculo.us, combined and compressed
- CSS fixed-position headers
- Prototype loader for SyntaxHighlighter
Comments
Hey dude, cool post, kind of what i had in mind here. I almost missed the Search example. thanks man for showing it to us in action too. cool!
Just what i needed. Will be trying it out ASAP.
Password fields show ******* instead of actual text using this method.
That's default browser behaviour, unfortunately. I've worked out a solution, though. Check back in an hour. ;)
Well, that took a bit longer than expected, but I've come up with a solution. The alternative code checks to see whether the input field's type is "password". If so, it creates a new "text" input with some nifty event handlers which ensure that only one of the two inputs is visible at any one time.
Nice script, though it doesn't work in IE, which doesn't allow you to change the 'type' attribute on an input element.
Thanks for sharing that info, Andrew.
Almost works for textarea tags as well but requires the user to click twice on the text area. Any idea how to fix it?
It appears to work correctly, Dave, in Chrome at least (see jsfiddle.net/mQVkp).
One thing I'll add is that this code should be used as a polyfill. There are two ways to check for native placeholder support. Both are fine, so use the shorter form if you don't mind a few complaints from JSLint.
// short, readable way to check for `placeholder` support
'placeholder' in document.createElement('textarea')
// longer, less comprehensible check to keep Crock happy
Object.hasOwnProperty.call(document.createElement('textarea'), 'placeholder')