Providing Contextual Form Help with Mootools

I like many webdevelopers build a lot of forms. Forms are the bread and butter of web applications, and while making forms is getting easier for developers, users often still have a hard time with them. In these circumstances it is necessary to give them a help above and beyond ‘password’. Giving contextual feedback to users helps them understand what you are asking, and helps you the developer/designer communicate what you want the user to do. This reduces user frustration with obscure or difficult to understand labels. However, this all assumes you have useful help text. But lets not niggle about those details and get onto the how to part.

Adding help to the form helper

Show Plain Text
  1. $help = '<p class="help-text">Passwords should be 6-8 characters and must contain at least one non-letter.</p>';
  2. echo $form->input('User.password', array('type' => 'password', 'after' => $help));

This will create a form element, label and wrapping div that looks something like

Show Plain Text
  1. <div class="input password">
  2.     <label for="UserPassword">Password</label>
  3.     <input type="password" name="data[User][password]" value="" id="UserPassword" />
  4.     <p class="help-text">Passwords should be 6-8 characters and must contain at least one non-letter.</p>
  5. </div>

Making it pretty

While this will work its not very pretty. What we need is some CSS and Javascript to spruce it up. We’ll keep the CSS pretty basic and simple.

Show Plain Text
  1. form div {
  2.     clear:both;
  3.     position:relative;
  4.     padding:5px 0;
  5. }
  6. form div:after {
  7.     content : '.';
  8.     height:0;
  9.     display:block;
  10.     clear:both;
  11.     visibility:hidden;
  12.     padding:0;
  13.     margin:0;
  14. }
  15. form input {
  16.     width:150px;
  17.     float:left;
  18.     margin:0 0 0 8px;
  19. }
  20. form label {
  21.     width:150px;
  22.     text-align:right;
  23.     display:block;
  24.     float:left;
  25. }
  26. form div p.help-text {
  27.     padding:8px;
  28.     border:1px solid #CF9F6D;
  29.     background: #FFFFB2;
  30.     clear:both;
  31.     -moz-border-radius: 8px;
  32.     -webkit-border-radius: 8px;
  33.     border-radius: 8px;
  34. }
  35.  
  36. html.js form div p.help-text {
  37.     position: absolute;
  38.     top:-3px;
  39.     left: 400px;
  40.     visibility:hidden;
  41.     margin:0;
  42.     width:500px;
  43. }

That will get us some nice yellow help bubbles off to the side of our form elements. I didn’t design around IE, so if you use this CSS make sure you test it. The CSS without any javascript will still display the helper bubbles. This will allow the effect to gracefully degrade.

Making it fancy

Making it fancy is equally easy. I’ve tailored the above CSS to be compatible with what I wrote earlier about easily enabling progressive enhancement By using a simple class that grabs all the necessary elements and applies the proper events, we can even fancier Form elements. Its built with MooTools but should be easily portable to any other Javascript library.

Show Plain Text
  1. var FormHelper = new Class({
  2.     Implements : Options,
  3.  
  4.     options : {
  5.         'selector' : 'input[type=text], input[type=radio], input[type=password], textarea, select',
  6.         'mode' : 'focus',
  7.         'helpSelector' : '.help-text'
  8.     },
  9.     elements : [],
  10.  
  11.     initialize : function(options) {
  12.         this.setOptions(options);
  13.  
  14.         $$(this.options.selector).each(function(item){
  15.             var parent = item.getParent();
  16.             this.elements.push(parent);
  17.             if (this.options.mode == 'enter') {
  18.                 parent.addEvent('mouseenter', this.show.bindWithEvent(parent, this.options.helpSelector));
  19.                 parent.addEvent('mouseleave', this.hide.bindWithEvent(parent, this.options.helpSelector));
  20.             } else {
  21.                 item.addEvent('focus', this.show.bindWithEvent(parent, this.options.helpSelector));
  22.                 item.addEvent('blur', this.hide.bindWithEvent(parent, this.options.helpSelector));
  23.             }
  24.         }, this);
  25.  
  26.     },
  27. /**
  28.  * Show an element
  29.  *
  30.  * Is used as a mouseEnter event.
  31.  */
  32.     show : function(e, helpSelector) {
  33.         e = new Event(e);
  34.         this.addClass('active');
  35.         if (helpSelector) {
  36.             var fieldHint = this.getChildren(helpSelector);
  37.             if (fieldHint) {
  38.                 fieldHint.fade('in');
  39.             }
  40.         }
  41.     },
  42. /**
  43.  * Hide an element
  44.  *
  45.  * Is used as a mouseLeave event.
  46.  */
  47.     hide : function(e, helpSelector) {
  48.         e = new Event(e);
  49.         this.removeClass('active');
  50.         if (helpSelector) {
  51.             var fieldHint = this.getChildren(helpSelector);
  52.             if (fieldHint) {
  53.                 fieldHint.fade('out');
  54.             }
  55.         }
  56.     }
  57.  
  58. });

Currently all the helpers are visible on page load, adding one bit of Javascript and one bit of CSS and some alterations to our previous code we can make a nice gracefully degrading effect. I’m a big fan of graceful degradation whenever possible. Keeping things accessible is good for everyone in the end. If you don’t already have a domready event setup add one in now.

Show Plain Text
  1. window.addEvent('domready', function() {
  2.     var myForm = new FormHelper();
  3. });

This will build the FormHelper and add all the necessary events. In addition to hiding / showing our help bubbles it adds an active class to the containing div, providing another CSS hook.

Example

You can find an example of this in action here

The javascript class will be available in my gitHub. I will be adding in features as I find the need to build them. Or you could fork it and add features it.

Comments

getChildren does not work for me on mootools 1.2.1

lanG on 5/20/09

IanG: There is a demo page on the article, you can check the code there. Perhaps you forgot to pass a this in to specify scoping.

mark story on 5/21/09

Comments are not open at this time.