Unobtrusive in-field text labels
Warning: This post concerns Web interface development and may be appear as arcane to many. It also contains HTML and JavaScript examples that may not render properly in feed readers or importers like Facebook. Follow the link back to the original post if you’re having trouble.
In HTML user-input forms, it is not uncommon to see text fields with “labels” as grayed-out text in the field itself which disappear when clicked.

My search for “best practices” on this technique left me…wanting. Firstly, I wasn’t sure what to call it. Secondly, many implementations were riddled with problems, paramount of which was abominable degradation. I am no accessibility expert, but these solutions didn’t even try. Here are two of the most common, and unfortunately, the worst.
Trickle-down
Initially this method looked promising. You explicitly set the value of the field to your label string which trickles down to the defaultValue attribute. You can then use defaultValue to determine when to clear or reset the label. Problems:
- Mean to screen-readers, non-JavaScript browsers, and those who use them
- Mean to your controller/form processing code (it somehow has to know to ignore your labels when they’re posted as values)
- Mean to forms that edit existing data (did defaultValue come from the label or from real data? If it’s real, there is no way to default back to the label if the user removes the value)
- Depending on the implementation it can be obtrusive
Some of these issues can be resolved through code, but it’s not going to be pretty.
Hidden fields
This, uh, solution, displays a “throw-away” text field as the label. On click, it’s replaced by the real field. To the user it appears that the text just disappeared. This has all the problems above plus some:
- Really really mean to screen readers and non-JavaScript browsers (there will be duplicate fields with text already in them for no apparent reason)
- Really mean to controller/form processing code (it has to arbitrarily ignore entire fields, not just values)
- It’s unbelievably intrusive
- It’s just a horrible idea on par with suggesting users place and remove labeled Post-it notes when moving from field to field
A better way
First, there may be an Even Better Way, but I believe this address all of the problems above, both practical and conceptual. In a nutshell, you set the field’s title, which you should be doing for accessibility reasons anyway. Optionally add a “real” label tag linked by id to it’s input field. JavaScript then looks for titled fields with blank values, hides their labels, sets the value to the title, and binds focus and blur events to the field. These respectively clear and reset the label (by comparing the value to the title) when users click on or off. On form submit, if any of these fields’ values match their titles, they are cleared by some JavaScript. Benefits:
- Unobtrusive
- Graceful degradation (screen-readers and non-JS browsers can fall back on the real label or title attribute)
- Uses all field attributes for their intended purposes
- Places all responsibility/logic in one location, removing the need for controllers to treat certain values or fields specially
- No Post-it notes
A possible draw-back is that users cannot submit a value that matches the field’s title. If that’s a real problem, you could probably add some more checks to hack around it. But how often is someone’s first name First?
My implementation uses >= jQuery 1.3. Since we’re on the Web anyway, I thought I’d throw in a working example below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
<form id="form_field_label_example" action="" method="post"> <p> <label for="first_name">First</label> <input id="first_name" name="first" size="15" title="First" type="text" /> <label for="middle_name">Middle</label> <input id="middle_name" name="middle" size="8" title="Middle" type="text" /> <label for="last">Last</label> <input id="last" name="last" size="25" title="Last" type="text" /> </p> </form> <script type="text/javascript"> $(document).ready(function() { auto_label("form#form_field_label_example input[title][type=text]") }) function auto_label(str) { $(str).each(function() { // Hide the field's real label $('label[for=' + this.id + ']').hide() // Set the label text and color for blank fields if ( !this.value || this.value == this.title ) { this.value = this.title $(this).css('color', '#999') } // On focus of blank fields, clear the label text and reset the color $(this).focus(function() { if ( this.value == this.title ) { this.value = '' $(this).css('color', 'inherit') } }) // On unfocus of blank fields, restore the label text and color $(this).blur(function() { if ( !this.value ) { this.value = this.title $(this).css('color', '#999') } }) }) // Clear label text when submitting form $(str).closest('form').submit(function() { $(str).each(function() { if ( this.title && this.value == this.title ) { this.value = '' } }) }) } </script> |
May 03, 2010 at 6:30 PM
Thanks for the code!
Why did you close off the $(document).ready(function() right after
auto_label("form#form_field_label_example input[title][type=text]")?
without including the remaining functions? I'm a beginning jQuery learner and I am trying to understand your code.
Thanks,
Sam Miller
May 07, 2010 at 3:52 PM
Sam,
Normally javascript executes as soon the browser runs into it. However there is no guarantee that the entire DOM will have loaded by that point. Since jQuery is usually used for accessing DOM elements, one needs to be sure the DOM is all there. The "ready" function waits for the DOM to load, then executes, ensuring you have access to everything.
I put my auto_label function outside of "ready" because I'm only defining it - it doesn't matter if the DOM is loaded at that point. As long as the DOM is loaded when auto_label is actually called, everything will be okay.
I certainly could have included auto_label in "ready," but I find it helps me keep clear what's happening when if I separate "actions" from "definitions". As far as I know there's no compelling reason to do one or the other. Comes down to preference, really.
July 02, 2010 at 3:41 AM
Just what I was looking for, thanks.