Wednesday, April 22, 2009

Form hints

So I was perusing my delicious history the other day, and happened along this post: http://woork.blogspot.com/2008/04/improve-form-usability-with-auto.html I was bored, so I thought I'd hack together my own version, especially given that someone else has laid out the blueprints already! Wheel++ I kept in mind some of the comments from the original post, namely keeping the javascript unobtrusive. Here's a demo for download. On with the details: First we'll mark up a simple form:
<form action="" method="get" accept-charset="utf-8">
 
  <p>
    <div class='label-wrapper'><label for='email'>Email: </label></div>
    <div class='element-wrapper'>
        <input type='text' name='email' id='email' />
        <div class='form-hint' id='email-form-hint'>
          Enter your email address
        </div>
      </div>
  </p>
 
  <p>
    <div class='label-wrapper'><label for='foo'>Foo: </label></div>
    <div class='element-wrapper'>
        <input type='text' name='foo' id='foo' />
        <div class='form-hint' id='foo-form-hint'>
          Enter something here
        </div>
      </div>
  </p>
 
  <p>
    <div class='label-wrapper'><label for='bar'>Bar: </label></div>
    <div class='element-wrapper'>
        <input type='text' name='bar' id='bar' />
        <div class='form-hint' id='bar-form-hint'>
          Enter something here
        </div>
      </div>
  </p>
 
  <p><input type="submit" value="Continue →"></p>
 
</form>
Here we let you keep it simple, merely adding a div of class "form-hint" to add a hint to a field. Note also that the hint's ID must match the form field's ID, in the form of "[ID]-form-hint" Next we'll add some style:
<style type="text/css" media="screen">
  
  .form-hint-wrapper {
    background:#fff;
    padding:0;
    position:absolute;
    z-index:999;
  }
        
  .form-hint {
    background:#def;
    clear:both;
    padding:5px 10px;
    display:none;
  }
  
  /* thanks to http://www.csskarma.com/lab/css_arrows/ */
  .arrow-up {
    background:transparent none repeat scroll 0 0;
    left:10px;
    top:0;
    width:20px;
  }
  .arrow-up-1 {
    border-right:10px solid #def;
    border-top:10px solid #fff;
    float:left;
  }
  .arrow-up-2 {
    border-left:10px solid #def;
    border-top:10px solid #fff;
    float:left;
  }
  .arrow-up-1, .arrow-up-2 {
    height:0;
    overflow:hidden;
    width:0;
  }

</style>
Finally finish off with the javascript guts:
<script type="text/javascript" charset="utf-8" src="http://ajax.googleapis.com/ajax/libs/prototype/1.6.0.3/prototype.js">    </script>
<script type="text/javascript" charset="utf-8" src="http://ajax.googleapis.com/ajax/libs/scriptaculous/1.8.2/scriptaculous.js?load=effects,builder">    </script>

<script type="text/javascript" charset="utf-8">
  Event.observe(window, 'load', init_hints);
  
  function init_hints() {
    $$('.form-hint').each(function(hint){
      
      var hint_parent = hint.parentNode;
      hint_parent.makePositioned();
      
      var arrow_wrapper = Builder.node('div', {'class': 'arrow-up'},
        [
          Builder.node('div', {'class': 'arrow-up-1'}),
          Builder.node('div', {'class': 'arrow-up-2'})
        ]
      );
      
      hint_clone = hint.cloneNode(true);
      Element.setStyle(hint_clone, {'display': 'block'})
      
      var hint_wrapper = Builder.node('div', {'class': 'form-hint-wrapper', 'style': 'display:none'},
        [arrow_wrapper, hint_clone]
      );

      var el = $(hint.id.replace('-form-hint', ''));
      Event.observe(el, 'focus', element_focused);
      Event.observe(el, 'blur', element_blurred);

      hint.replace(hint_wrapper);
      
    });
  }
  
  function element_focused(el) {
    var wrapper = $(el.target.id + '-form-hint').parentNode;
    new Effect.Appear(wrapper, {'duration': 0.25})
  }
  
  function element_blurred(el) {
    var wrapper = $(el.target.id + '-form-hint').parentNode;
    new Effect.Fade(wrapper, {'duration': 0.25})
  }
  
</script>
The script will find all elements on the page of class "form-hint", then wrap them in another div that contains an arrow pointing to the form element, using only CSS. That's about it - feel free to hack the CSS to change the hint colors, etc... Download the demo.