Close and Go BackBack to Viget

A Better jQuery In-Field Label Plugin

Trevor Davis
Trevor Davis , ON THE TOPIC OF Javascript
2/11
2010
29

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.

Keith Muth said on 02/11 at 12:18 PM

This is a really cool plugin, thanks for reminding me about it. In your example if you disable JavaScript the label stays inside the field. I think taking out the absolute positioning inside the CSS on “form p label” works better because label then appears above the field when JavaScript is disabled since the JS is handling all the positioning. Not sure what you think about that. Let me know, and thanks for the example!

Les James said on 02/11 at 12:18 PM

I just want to say that this is awesome! I’m so implementing this on my current project. Thanks for sharing!

Jeremy Frank said on 02/11 at 12:54 PM

Thanks Trevor, great write-up. If you wanted to go the HTML5 route, you could possibly do feature detection on the placeholder attribute. If supported, use the browser defaults, if not supported then use your JavaScript label technique. I’ve wanted to write some code or a plugin to do just this, but I haven’t had the time yet!

Trevor Davis said on 02/11 at 01:03 PM

@Keith-
Which example are you talking about? The way Doug’s original plugin works?

@Jeremy-
You know, as I was publishing this, I was thinking the same thing. But after reading the spec, the placeholder attribute is not supposed to replace the label element, so you should still be using labels. I guess if the browser supports placeholder, then you could just hide the label, but it seems like you are doing extra work when just positioning the label solves the problem for all browsers. Oh well, I guess it’s not too much extra code to add a check for the placeholder attribute.

Keith Muth said on 02/11 at 01:04 PM

I was talking about the example you put up on GitHub

Jeremy Frank said on 02/11 at 01:21 PM

@Trevor
Yes, definitely, still always labels with inputs. I guess I was thinking in a different context, where you have a form that always displays a label to the left (or above) the field. eg:

Email Address: [email@example.com ]
Phone Number: [(xxx) xxx-xxxx ]

In that case, the placeholder shows the format that you are looking for (a short hint, as the spec says), and it works in tandem with the displayed label.

The extra code required to do the html5 feature detection and alternate technique probably wouldn’t be worth it on a client’s production site, but for experimental stuff, it would be fun to play around with!

Aaron K. said on 02/11 at 01:53 PM

Nice write-up! I feel compelled to point out a jQuery plugin that I developed a few years ago called ToggleVal, and have been continually adding features to since then. It adds a number of ways to get the desired effect from the first few examples above. Check it out on Github (documentation and options are on the Wiki page): http://github.com/akuzemchak/toggleval

Nick Husher said on 02/11 at 01:57 PM

I see no reason why, in the first example where you set the value, it’s so difficult to catch form submit events and clear form elements without valid entries in them. This would be a handful of lines of jQuery that would be clear and self-documenting. If you even wanted to get fancy, you could use the placeholder attribute instead of the title and simply check if the browser supports placeholders (currently, only webkit browsers) before executing any code.

BTW: You can check to see if the browser supports placeholders by doing this: (typeof doc.createElement(’input’).placeholder == ‘undefined’)

Trevor Davis said on 02/11 at 02:12 PM

@Keith-
Thanks, I never modified his example page, but I should go back and do that.

@Jeremy-
True, if you want to use for formatting tips instead of labels you could do that.

@Aaron-
Thanks for sharing.

@Nick-
Not saying it’s difficult to check to check to see if the value equals to title attribute, but it seems like the wrong approach since the fields should already have labels.

Patrick Clarke said on 02/11 at 02:12 PM

Smart idea. I’ve been setting the initial value in my source and clearing on a focus for quite some time. This makes things much simpler.

David DeSandro said on 02/11 at 06:37 PM

Trevor, thanks for taking the time to look into this. HTML forms require so much careful attention

I really like your final solution.  My one gripe is that, like Mr. Frank, I would want the labels to stay as labels, and use place-holders inside the field.

Taking on the rel/abs positioning idea, I applied it using background color to show or hide the place-holder. Before diving into this I thought I could do it all without any JS, but alas, the :empty selector does not function dynamically on text inputs. Take a look:

http://desandro.com/demo/infield-label.html

Of course, this approach result doesn’t play nice with IE6 & 7, but that can be addressed separately.

The topic is “In-field labels” and there is not one baseball pun? My inner corny-joke-dad is shaking his head.

Trevor Davis said on 02/11 at 07:13 PM

@Dave-
Interesting, thanks for the demo page. I guess my post topic is slightly different than what you and Jeremy were trying to accomplish because you want the label to still be visible in addition to the placeholder. So I guess it just depends on what your form requires.

I hadn’t thought about using a background color to manipulate the placeholder, but that’s an interesting idea. If you are absolutely positioning the form field, it seems like you could play around with z-index as well.

Well, where’s your baseball pun? Should I say that baseball puns are safe in the comments?

anistock said on 02/12 at 12:15 PM

expert article, very informative

Matt Latzke said on 02/13 at 08:26 PM

The quickest and easiest way I’ve found is to use the “defaultValue” attribute:

http://www.lightburndesigns.com/blog/clearing-input-via-javascript/

Douglas Neiner said on 02/14 at 12:12 AM

@Trevor, awesome write up! I feel horrible I haven’t reviewed the pull request yet, but I hope to have your changes merged in soon! 

The only other thing I need to make clear in the docs, is that it if possible, you’ll have better luck positioning the label “under” the text input instead of over. If it is under, right clicking on the text field still yields “Copy, Paste, etc” whereas right clicking when the label is over doesn’t give the correct context menu. Perhaps I’ll add that as an option in addition to your changes.

Trevor Davis said on 02/16 at 09:57 AM

@Matt-
Are you using defaultValue instead of a label?

@Doug-
No worries about not reviewing the pull request yet. I hadn’t even thought about the context menu, but that would be a nice option to add in.

Matt Latzke said on 02/16 at 12:21 PM

@Trevor-
Yeah, I am.  I realize that this isn’t the best for accessibility and that there should be a label tag associated with the field.  Using defaultValue essentially fills the role that the placeholder attribute would play in the HTML5 example.

Here’s an example of it in action: http://www.lightburndesigns.com/input.html

Also, Here’s the link to my write up again (with a link this time!)

Trevor Davis said on 02/16 at 01:24 PM

@Matt-
Nice example. defaultValue is a nice substitution for placeholder and seems similar to the title example that I gave at the beginning of the post. I guess the one downside (along with my title example) is that you need to validate to make sure the defaultValue is not what is submitted in the form.

Scott Mill said on 02/17 at 12:37 PM

This is a nice idea, I might well implement it myself whenever I find the time to actually build myself a proper site.

Tim said on 02/18 at 07:39 PM

@Scott: building your own site is always a problem ;-)! Thanks for this plugin, saved to my jQuery favorites.

Brett said on 02/18 at 11:59 PM

Very good idea, I’ve added it to my code snippets.

Thomas Kaldhol said on 02/19 at 04:27 AM

Great plugin!
I suggest you edit the HTML5 example to input type="email".

Gerrit Fries said on 02/19 at 10:43 PM

I love the fading effect! Here is what I have done so far: http://since1985.de/jq/06_infield_labels/index.html

Martin said on 04/03 at 02:00 PM

Hi, I’ve been searching for the perfect jquery inline-label plugin but I still can’t find anything that works like this one:

https://launchpad.37signals.com/signin

Unfortunately it uses the Prototype framework. If someone can make the same with jquery, it would be great :)

Trevor Davis said on 04/03 at 03:43 PM

@Martin-
This plugin will do everything that the 37 Signals one does.

Martin said on 04/03 at 04:23 PM

Hi Trevor.

Yes, it’s almost the same as 37 Signals’ one, but there are 2 important differences:

- Saved logins (autocomplete?) - let’s say you have 2 different logins that are saved by the browser. When you start typing your username, a drop-down appears, offering you to choose a login. You select from the drop-down menu and the username and password fields are populated. Then the infield labels should disappear.

- Clearing the input field using backspace - it’s a good thing to have the label reappear.

This second issue is solved in the jLabel plugin (http://www.wduffy.co.uk/jlabel/) but I still don’t like it because it doesn’t solve the Saved logins problem.

I hope my English is not very bad :)

Trevor Davis said on 04/03 at 08:06 PM

@Martin-
You could certainly modify the plugin even further to add in that additional functionality.

Narga said on 04/06 at 11:33 PM

I’ve wrote a small jQuery and CSS code allow you make your own Awesome Form’s Inline Labels without the plugins
http://www.narga.net/making-awesome-forms-inline-labels-with-jquery/

Trevor Davis said on 04/06 at 11:37 PM

@Narga-
Your example runs into the same issues that my first example does. Since you are setting the value attribute of the fields to be the label, you need to validate the form to make sure people aren’t submitting the labels as real values.

Commenting is not available in this weblog entry.

We're The Designers

at Viget Labs. We write about design news, trends, techniques, buildout, inspiration, CSS, and our projects.

What's a-twitter?

Follow us @VigetInspire for updates of the goings-on here or @Viget for more from all of the Viget crew. #thatisall

Recent Comments

We use it a lot at Hashrocket now. It’s made life a lot easier when coding large-scale applications.

The hardest part of SASS is going back to coding regular CSS after you’ve been in it...

Subscribe to Comments RSS RSS

Contact Us

Have any questions, comments, ideas, or secrets to share? Let us know.


How many days in a non-leap year?

Sorry, you need to have Javascript enabled to use this form. (Don't blame us, blame the spammers!) If you'd like to contact us, please visit our Contact page.