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 — < time datetime="2010-04-15T12:59:00+00:00">15 April 2010
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;
}
});
}
});
});
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.