A Better jQuery In-Field Label Plugin
Trevor Davis, Former Front-End Development Technical Director
Article Category:
Posted on
The hip trend these days is to use in-field labels on form fields. What are in-field labels you ask? I'm sure you've seen something like this recently:
This is a pretty nice effect, and it can really help to save space on forms. There are a billion different ways to implement this, and I don't suggest you use the example from above because that was just a quick way to show the effect. So let's walk through a couple of different implementation approaches and figure out the best way to implement this feature.
Title Attribute
This is the approach that I used to take. I would add a title attribute to the input element and copy that value into the value attribute.
Example
<input type="text" name="example-1" id="example-1" title="Email Address" />
Without JavaScript, this field just looks like an empty form field:
So let's add a bit of jQuery that copies the title attribute to the value attribute. When the field is focused, if the value of the form equals the title attribute, we will clear the value. When focus is removed from the field, if the value of the form equals nothing, we will add the title attribute back in.
Here is the JavaScript necessary to complete something like that:
$(':input[title]').each(function() { var $this = $(this); if($this.val() === '') { $this.val($this.attr('title')); } $this.focus(function() { if($this.val() === $this.attr('title')) { $this.val(''); } }); $this.blur(function() { if($this.val() === '') { $this.val($this.attr('title')); } }); });
So that gives us the desired functionality, but then we need to think about what happens when you submit the form. If a user doesn't fill in any form fields, it is going to save all of those title attributes as values to the form. You could go back and check to make sure that the value does not equal the title attribute before allowing the form to submit, but that adds additional work.
I do like adding the title attribute to form fields, because I think it is useful to show the label for the field when you are hovering over it. But clearly, this approach is not ideal.
Placeholder Attribute
With HTML5 becoming more and more prevalent, we get the placeholder attribute. It's sole purpose is to do exactly what we want:
The placeholder attribute represents a short hint (a word or short phrase) intended to aid the user with data entry. A hint could be a sample value or a brief description of the expected format.
Example
Well that sounds great, but since it requires HTML5, it's not supported in all browsers. If you are using a Webkit browser, you can check out this demo (sorry, we aren't using HTML5 here, yet). Here is the code we are using on the example page:
<input type="text" name="example-2" id="example-2" placeholder="Email Address" />
The Label Element
Another solution, and the one that we have been using, is to absolutely position the actual label element overtop of the form field. When the form field is focused, the label fades away.
We have found Doug Neiner's In-field plugin to be one of the better in-field label plugins out there. However, when I started using it on a recent project, I had some accessibility concerns:
- You absolutely position the label in your CSS, so if someone does not have JavaScript enabled, they have a label overtop of their form field, and it never goes away.
- If you have a dark background, your text color is white, and your input fields are white; you have to explicity set the color of your label so that you can see it when positioned over the form field.
Here is what a field would look like if you styled it like the plugin requires and JavaScript turned off:
Having the label over the input field and never going away could really prevent a user without JavaScript enabled form successfully submitting the form.
To address these concerns, I made some modifications to Doug's plugin.
First, I changed it so that the labels are being absolutely positioned via JavaScript. So you may see a quick flash of the form like this before it would jump into position:
One solution to minimize this problem is to use Paul Irish's technique for fighting FOUC.
Then, you can absolutely position the label only when the html element has the js body class:
.js label { position: absolute; }
Next, I didn't like how it was a requirement to have a wrapper that was relatively positioned around each form field (even though that is pretty common). So I got the position of the form field relative to its first positioned ancestor, and used that to position the label.
base.$label.css('position','absolute'); var fieldPosition = base.$field.position(); base.$label.css({ 'left' : fieldPosition.left, 'top' : fieldPosition.top }).addClass(base.options.labelClass);
Finally, I added a class to the label when it is postioned over the field. This was useful, because I had a form that had a div that had a red background and all of the text inside of it was white (including the label), and the form fields have a white background. So when JavaScript it turned off, everything looked okay. But when JavaScript was enabled, it was putting a white label over a white form field.
To solve this, I could use the the same teqnique as above: the js class on the HTML element, but I figured it would be more useful to others to build in a class that could be styled. So by default, a class of infield is added to a label when it is positioned over the field, but you can customize the class in the options.
Example
So let's take a look at this in action (you can disable JavaScript and see that this example is more accessible):
Get the Updated Plugin
I forked Doug's code on GitHub to incorporate these changes, so you can download it from there.
What do you think? Can you think of a better method? What other methods have you tried to accomplish this functionality? Let's discuss in the comments.