Creating Self-Contained Field Labels (With or Without jQuery)

Tuesday, September 20, 2011

Sometimes you have to pack a lot of content onto a page, which can present design challenges when trying to make it all fit while still being legible. If you have some forms in your layout (login forms, newsletter sign ups, etc) you can save a bit of space by moving the field labels inside of the field. Here's an example of a typical login form:

  1. <form name="awesomeLoginForm" action="">
  2. <label for="username">Username</label>
  3. <input type="text" id="username" name="username" />
  4. <label for="password">Password</label>
  5. <input type="text" id="password" name="password" />
  6. <input type="submit" value="Go" />
  7. </form>

Which could end up looking something like this (depending on your style sheet):


Here is a Javascript function I wrote that will capture the label values for the field inputs, and place those inside the fields themselves.

The Regular Javascript Version

  1. function setSelfContainedFieldLabels(objs)
  2. {
  3. var labelElems = document.getElementsByTagName('LABEL'),
  4. key,
  5. key2,
  6. hideShowText = function(key, focus)
  7. {
  8. var elem = objs[key].elem,
  9. re = new RegExp('^(\s?|' + RegExp.escape(objs[key].value) + ')$'),
  10. blurColor = objs[key].blurColor || '#bbb',
  11. elemVal = (elem.value.match(re)) ? (focus ? '' : objs[key].value) : elem.value,
  12. color = (elemVal === objs[key].value) ? blurColor : objs[key].color;
  13. elem.value = elemVal;
  14. elem.style.color = color;
  15. };
  16. for(key in objs) {
  17. if (objs.hasOwnProperty(key)) {
  18. objs[key].elem = document.getElementById(objs[key].id);
  19. // find the label for this element, capture the value, and hide it via css
  20. for (key2 in labelElems) {
  21. if (labelElems.hasOwnProperty(key2)) {
  22. if (labelElems[key2].htmlFor == objs[key].id) {
  23. // if the value property is defined, override the form element's label value
  24. if (objs[key].value) {
  25. objs[key].elem.value = objs[key].value;
  26. } else {
  27. objs[key].elem.value = objs[key].value = labelElems[key2].innerHTML;
  28. }
  29. labelElems[key2].style.display = 'none';
  30. break;
  31. }
  32. }
  33. }
  34. objs[key].color = objs[key].elem.style.color;
  35. // add onfocus and onblur event handlers
  36. objs[key].elem.onfocus = function(arg)
  37. {
  38. return function()
  39. {
  40. hideShowText(arg, true);
  41. }
  42. }(key);
  43. objs[key].elem.onblur = function(arg)
  44. {
  45. return function()
  46. {
  47. hideShowText(arg, false);
  48. }
  49. }(key);
  50. hideShowText(key);
  51. // set an onsubmit event handler to the form
  52. // to set the field value to blank when submitted
  53. // if nothing was entered
  54. if (objs[key].elem.parentNode.tagName === 'FORM') {
  55. objs[key].elem.parentNode.onsubmit = function(arg)
  56. {
  57. return function()
  58. {
  59. hideShowText(arg, true);
  60. }
  61. }(key);
  62. }
  63. }
  64. }
  65. }

You will also need the following RegExp.escape function in order to make this work. RegExp.escape is blatantly "borrowed" from this website, and is needed to escape characters in the field labels that would cause the regular expressions used to not work:

  1. // prepares a string for a regex escaping regex metacharacters
  2. RegExp.escape = function (text) {
  3. return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
  4. }

The function is implemented by attaching it to a window.onload event handler like so:

  1. window.onload = (function(){
  2. setSelfContainedFieldLabels([
  3. {id: "username"},
  4. {id: "password", value: "Pswd", blurColor: "red"}
  5. ]);
  6. });

Notice that the function takes one argument: an array of anonymous objects. The objects must have at least one property - the id property. This is the id assigned to the form field. Other optional properties are value, which if defined will override the label's text, and blurColor, which defines the color of the text when a user hasn't entered anything into the field.

In Action

OMG look at all that space we freed up! There is only one "gotcha" that I'm aware of: This function sets the field values to blank when the form is submitted if the user hasn't entered anything. The problem is that (in our example) if a user's username IS "Username", the field would be reset to blank. This may or may not be desired behavior depending on the needs of your form, but to remove this part take out the following lines:

  1. if (objs[key].elem.parentNode.tagName === 'FORM') {
  2. objs[key].elem.parentNode.onsubmit = function(arg)
  3. {
  4. return function()
  5. {
  6. hideShowText(arg, true);
  7. }
  8. }(key);
  9. }

For jQuery users, here is a jQuery version - this has been tested on version 1.6.3

The jQuery Version

  1. function setSelfContainedFieldLabels(objs)
  2. {
  3. var label,
  4. parentForm,
  5. hideShowText = function(key, doFocus)
  6. {
  7. var obj = objs[key],
  8. re = new RegExp('^(\s?|' + RegExp.escape(obj.value) + ')$'),
  9. blurColor = obj.blurColor || '#bbb',
  10. elemVal = (obj.elem.val().match(re)) ? (doFocus ? '' : obj.value) : obj.elem.val(),
  11. color = (elemVal === obj.value) ? blurColor : obj.color;
  12. obj.elem.val(elemVal);
  13. obj.elem.css('color', color);
  14. };
  15. jQuery.each(objs, function(key, obj) {
  16. obj.elem = $('#'+obj.id);
  17. // find the label for this element, capture the value, and hide it via css
  18. label = $('label[for="'+obj.id+'"]');
  19. if (label) {
  20. // if the value property is defined, override the form element's label value
  21. if (obj.value) {
  22. obj.elem.value = obj.value;
  23. } else {
  24. obj.elem.value = objs[key].value = label.html();
  25. }
  26. label.css('display', 'none');
  27. }
  28. obj.color = obj.elem.css('color');
  29. // add onfocus and onblur event handlers
  30. obj.elem.focus(function(arg)
  31. {
  32. return function()
  33. {
  34. hideShowText(arg, true);
  35. }
  36. }(key));
  37. obj.elem.blur(function(arg)
  38. {
  39. return function()
  40. {
  41. hideShowText(arg, false);
  42. }
  43. }(key));
  44. hideShowText(key);
  45. // set an onsubmit event handler to the form
  46. // to set the field value to blank when submitted
  47. // if nothing was entered
  48. parentForm = obj.elem.parent('form');
  49. if (parentForm) {
  50. parentForm.submit(function(arg)
  51. {
  52. return function()
  53. {
  54. hideShowText(arg, true);
  55. }
  56. }(key));
  57. }
  58. });
  59. }

You can set this to run when the document is loaded like so:

  1. $(document).ready(function(){
  2. setSelfContainedFieldLabels([
  3. {id: "username"},
  4. {id: "password", value: "Password", blurColor: "red"}
  5. ]);
  6. });

Posted by Aaron Fisher at 2:12pm

0 Comments RSS

Login To Post A Comment

Don't have an account yet? Sign Up