Summary

Thrusting new windows upon visitors of your site is frowned upon, as it goes against device independence by assuming a windowed environment. One situation where developers feel that a new window is appropriate is with web forms. If the visitor requires help on a form field, a new window saves the visitor the trouble of having to leave the form, and possibly losing the data they have entered. This article illustrates a scripting technique to get around the problem without having to open a new window.

Author: Gez Lemon

Contents

Introduction

I don't intend to start a debate about popup windows, but the three biggest complaints about popups are that they're obtrusive, can disorientate/confuse the user, and assume a windowed environment, which goes against the principles of device independence. Put simply, a user can choose to open a link in a new window or new frame if the author has marked up the document without specifying a target for the link, but cannot easily open the link in the same window if the author has marked up the document to open the link in a new window.

The Form Problem

One situation where authors like to use popup windows is providing help for web forms. If a link to a help document opens in the same window, the data entered so far may be lost if the visitor follows the link in the same window. One solution to this problem is to put the help at the end of the current document, and provide in-page links. When the user navigates back to where they were stuck, the information is still in the form, as they've never left the current document. The problem with this approach is that it ruins the design, and understandably upsets the designers. Another solution is to put lots of helpful information by the side of each form element explaining in detail what is required. This not only suffers from the previous problem of upsetting the designers, but also results in information overload for some visitors who may be put off by the bulk of the resulting form.

The ideal situation would be to put the information by each form field, but only when the user requests help. This means that the form data stays in tact, as the user hasn't navigated away from the page; the designers are happy, because they only see their original design; we're happy because everyone else is happy. The rest of this article shows a scripting technique to achieve this. The Mock Number Transfer system illustrates this technique in practice.

Basic Markup

To begin, we'll assume the worst-case scenario that visitors have neither CSS nor scripting enabled. For these visitors, we'll provide the help as footnotes at the bottom of the page. The only downside of this technique is that we require some redundant markup as hooks so that we can manipulate the data with our script for those visitors that do have scripting enabled.

The whole help section is contained within a div element, and the help text for each form element is also in its own div. The reason for this is so that we can move the help text as a single item, regardless of how much content it contains, and remove the container when we have finished. Notice that the links back to the associated form fields are outside of the div containers: the reason for this is that the links wouldn't make sense once we've moved the content, so we leave them behind so that they are removed with the container.

<div id="helpcontainer">
    <h2>Help Section</h2>
    <div id="firsthelpfieldid">
        <h3>First form field help</h3>
        <p>
        Explanation for first form field.
        </p>
    </div>
    <p>
    <a href="#fid">Back to first input field</a>.
    </p>

    <div id="secondhelpfieldid">
        <h3>Second form field help</h3>
        <p>
        Explanation for second form field.
        </p>
    </div>
    <p>
    <a href="#sid">Back to second input field</a>.
    </p>
</div>

The only other markup required are the links by form elements that require help, whose href attribute will point to the associated help text:

<a href="#firsthelpfieldid">Help for field 1</a>

Adding the Script

If scripting isn't enabled, then the form will display a series of links that point to the appropriate help text, with a link back to the associated form element. If scripting is enabled, no help text will be displayed unless requested by the user.

The following outlines the steps we need to make this work:

The following is the complete script:

function addHelp()
{
  var strID, objHelp;

  // Check we're working with a DOM compliant browser
  if (document.getElementById && document.appendChild && document.removeChild)
  {
    var objHelpform = document.getElementById('transfer');
    
    var objAnchors = objHelpform.getElementsByTagName('a');
    
    // Iterate through all anchors in the form
    for (var iCounter=0; iCounter<objAnchors.length; iCounter++)
    {
      if (objAnchors[iCounter].className != 'leave')
      {
        // Locate the associated help text's container,
        // and hide it
        strID = getIDFromHref(objAnchors[iCounter].href);
        objHelp = document.getElementById(strID);
        objHelp.style.display = 'none';

        // Add events to reveal/hide
        objAnchors[iCounter].onclick = function(event){return expandHelp(this, event);}
        objAnchors[iCounter].onkeypress = function(event){return expandHelp(this, event);}

        // Move beneath current form field
        objAnchors[iCounter].parentNode.appendChild(objHelp);
      }
    }
    
    // Remove the remainder of the old help section
    var objOldnode = document.getElementById('helpcontainer');
    
    objOldnode.parentNode.removeChild(objOldnode);

    // Release memory to prevent IE memory leak
    // Thanks to Mark Wubben <http://novemberborn.net/>
    // for highlightint the issue
    objHelpform = null;
    objHelp = null;
    objAnchors = null;
  }
}

// Return the ID of the element from the "href" attribute
function getIDFromHref(strHref)
{
  var iOffset = strHref.indexOf('#') + 1;
  var iEnd = strHref.length;

  return strHref.substring(iOffset, iEnd);
}

function expandHelp(objAnchor, objEvent)
{
  var iKeyCode;

  // If from the keyboard, check the user is
  // activating it rather than tabbing through
  if (objEvent && objEvent.type == 'keypress')
  {
    if (objEvent.keyCode)
      iKeyCode = objEvent.keyCode;
    else if (objEvent.which)
      iKeyCode = objEvent.which;
    
    if (iKeyCode != 13 && iKeyCode != 32)
      return true;
  }

  strID = getIDFromHref(objAnchor.href);
  objHelp = document.getElementById(strID);

  // Toggle on and off
  if (objHelp.style.display == 'none')
    objHelp.style.display = 'block';
  else
    objHelp.style.display = 'none';

  return false;
}

Category: Scripting.

Comments

  1. [form-help-without-popups.html#comment1]

    Excellent! I love how the help text shows up next to the form element, but degrades to a section separate from the form.

    Posted by Matthew on

  2. [form-help-without-popups.html#comment2]

    Nice idea. Just one small note, there's a memory leak (in IE) where you define the event handlers. Set 'objAnchors' and 'objHelp' to 'null' before the function ends to prevent this.

    Posted by Mark Wubben on

  3. [form-help-without-popups.html#comment4]

    Just one small note, there's a memory leak (in IE) where you define the event handlers. Set 'objAnchors' and 'objHelp' to 'null' before the function ends to prevent this.

    Thank you for the pointer, Mark. I've updated the script.

    Would it be better to also supply the question mark image with a title attribute?

    That's a good idea, Robert - maybe even update it with the script to explain the toggle nature of the help when scripting is applied. I've left it as it if for simplicity, but that would aid usability.

    Posted by Gez on

  4. [form-help-without-popups.html#comment7]

    Think about the Usability.. Many many critical points..

    This technique aids usability. If you have serious usability concerns, state what they are and stop trolling!

    Posted by tj on

  5. [form-help-without-popups.html#comment9]

    Nicely done Jez! AND, it works better than I expected with assistive technology. Since a script is involved, I almost expected screen readers to react in their usual way ... re-reading from the top of the screen.

    Jaws 6.1 and IBM HPR 3.04 handle the example page with ease. No re-reads.

    Yet, a small problem remains. Sighted people can easily see the help icon. The unsighted person doesn't know the help is available because it follows the actual control. The person who might most need the help isn't aware that it's there. hmmmm...

    For Robert Wellock: It depends on what you're getting at. If it is to help the sighted person understand the well-known meaning of a question mark, I suppose TITLE might help a little. For people using assistive technology, the ALT attribute is the correct one to use for an image. Additionally, some screen readers do not automatically read TITLE attributes unless a person digs down three levels deep to turn the option on. For more on this aspect see: Access Matters Quiz 1.1.8: ALT text or Title text? http://www.access-matters.com/2005/10/01/quiz-118-alt-text-or-title-text/

    Posted by Bob Easton on

  6. [form-help-without-popups.html#comment10]

    Hi Bob,

    Thank you for the feedback on how it works with screen readers.

    Yet, a small problem remains. Sighted people can easily see the help icon. The unsighted person doesn't know the help is available because it follows the actual control. The person who might most need the help isn't aware that it's there. hmmmm...

    That's a good point, and one that I didn't consider. My first thought that was that the link could be placed in the label element. The markup would be valid, but I'm not sure of its semantic value, as the behaviour would be unexpected. I'm also not sure how that would work with assistive technology. The script would require a trivial amendment to allow for the fact that the anchor is contained within a label element:

    objAnchors[iCounter].parentNode.parentNode.appendChild(objHelp);

    I'll have a think about it, and see if I can think of anything that would work. Thank you again for the feedback.

    Posted by Gez on

  7. [form-help-without-popups.html#comment11]

    Nice idea.

    The unsighted person doesn't know the help is available because it follows the actual control. The person who might most need the help isn't aware that it's there.

    The unsighted person will know - there is a message above the form saying there are help icons. One tab and they have it.

    Posted by Mitch on

  8. [form-help-without-popups.html#comment13]

    Hi Vitaly,

    I am not sure there will be no problems with usability and accessibility, but still - an interesting technique!

    The general idea was to improve usability, and ensure that the technique is accessible to all. The technique degrades nicely when support for scripting isn't available or not enabled, is device independent, and works as expected with assistive technologies. The alternative is to either provide the information inline, which has a negative impact on usability as it would make the form look far more intimidating to the user, or open the help text in a popup window.

    Are you referring to a particular usability or accessibility problem, or do you just have a hunch that it will cause problems?

    Posted by Gez on

  9. [form-help-without-popups.html#comment14]

    This didn't seem to work in Firefox 1.0.7 on my box but seemed to work fine in IE 6. Anyone else have this problem? Would love to use this if it was cross-browser compatible.

    Posted by Ren on

  10. [form-help-without-popups.html#comment17]

    Has anyone seen or compared the BBC Collective's approach to this problem? Try going to http://www.bbc.co.uk/dna/collective/ and click on the link [create your membership].
    Two things that struck me about it, firstly how appalling the code was underneath the page. And secondly on a more positive note the inclusion of an audio explanation of each of the form elements.

    There are in total 3 means to present help info to the user for each form element. The 'standard' popup links to help files; an on-focus hide/visible CSS div tag and the audio one.

    As all three bits of info are almost exactly the same, I'm sure that it just completely defeats the objective the designers thought they were trying to meet.

    Posted by Robert Campbell on

  11. [form-help-without-popups.html#comment18]

    This should be more focused on the usability aspect than a DOM break-thru. Just from the looks of the example, it's nothing more than toggling the display of block full of information.

    Agreed that it's definitely a usability booster. It's just funny to see that there's a whole download script and the other 9 yards for just that.

    Posted by Dustin on

  12. [form-help-without-popups.html#comment19]

    Dustin,

    This should be more focused on the usability aspect than a DOM break-thru. Just from the looks of the example, it's nothing more than toggling the display of block full of information.

    Nowhere in the post is it claimed that this technique is a DOM break through. The whole focus of the post is on improving usability with scripting.

    Agreed that it's definitely a usability booster. It's just funny to see that there's a whole download script and the other 9 yards for just that.

    If you know of a technique to achieve the same results that doesn't require scripting, please let me know. Or are you suggesting usability isn't important enough to require a scripting solution? If so, what's the problem with scripting; are you suggesting it's too much to expect from an author?

    I can't quite work out what your problem with the post is, but you're obviously not alone. Some think it's too complex, others not complex enough to warrant writing about. You apear to think it's both, or have I misunderstood your point?

    Posted by Gez on

  13. [form-help-without-popups.html#comment20]

    Gez,
    Excuse my cranky mood at 3am last night. I've been indulged in heavy DOM scripts lately that have come off like breakthrough's at work... entirely not your fault.

    This method definitely beats popups and it's good that you brought it up. It's the simple things that can aid usability (and in fact accessibility for the sake of a non-javascript browser).

    What is my problem? Let's just keep it mine, because it's not yours *wink*

    Posted by Dustin on

  14. [form-help-without-popups.html#comment21]

    Great idea!

    One thing though, where you have:

    var objHelpform = document.getElementById('transfer');

    have you thought about just putting:

    var objHelpform = document.forms[0];

    if you do it my way, then the user wont have to change the "id" of the form, it can be anything, just as long as it is the first form in the document.

    just a thought. none-the-less, great idea *smile*

    Posted by Drew Decker on

  15. [form-help-without-popups.html#comment22]

    Hi Drew,

    Thank you for your comment.

    One thing though, where you have:

    
    var objHelpform = document.getElementById('transfer');
    

    have you thought about just putting:

    
    var objHelpform = document.forms[0];
    

    The forms collection is a proprietary Microsoft extension (supported by most browsers) that isn't part of the W3C's DOM. When XHTML content is served as application/xhtml+xml, the forms collection isn't available. For that reason, I prefer to use DOM methods so that the only thing that needs to be changed for strict XHTML is the namespace for the XML methods.

    Posted by Gez on

  16. [form-help-without-popups.html#comment23]

    Hi Gez,

    I would consider leaving in the link at the end of the help sections even when script is supported. It can be difficult for screen reader users to know when they have reached the end of these sections, depending on the content that follows. The link back to the form control could be implemented as a graphic (with appropriate text alternative of course) to make it a little less offensive to the designers.

    Sofia

    Posted by Sofia Celic on

  17. [form-help-without-popups.html#comment24]

    Hi Sofia,

    I would consider leaving in the link at the end of the help sections even when script is supported. It can be difficult for screen reader users to know when they have reached the end of these sections, depending on the content that follows.

    I didn't consider that, but it's a good point. To cater for that wouldn't require a change to the script, but the link back to the form field would need to be grouped within the associated div:

    <div id="firsthelpfieldid">
        <h3>First form field help</h3>
        <p>
        Explanation for first form field.
        </p>
        <p>
        <a href="#fid">Back to first input field</a>.
        </p>
    </div>

    Posted by Gez on

  18. [form-help-without-popups.html#comment25]

    Just to keep everyone up-to-date with this technique; Sofia Celic gave me some ideas about how the script could be improved. They are great ideas, and I will produce another version of the script that includes some of the usability enhancements Sofia has suggested when work quietens down a bit, but she also mentioned a couple of problems with the script as it is.

    Sofia pointed out that when I moved the section of code that retrieves the id from the href attribute, I forgot to copy across the variable declarations, leaving them in the addHelp function, along with a redundant variable that was no longer required. The published script here, along with the script used in the example, has been updated to declare the variables correctly.

    Sofia also mentioned that merely including the link back to the associated form control wasn't enough; it doesn't work. Mea culpa; I should have tested it worked as expected before saying that no amendment to the script would be required. The script iterates through each anchor element, so would require amending so as not to include the links back to the associated form controls. There are several ways of doing this, but the simplest method would be to add a class attribute to the links in the help section indicating that they do not require processing:

    <div id="firsthelpfieldid">
        <h3>First form field help</h3>
        <p>
        Explanation for first form field.
        </p>
        <p>
        <a href="#fid" class="leave">Back to first input field</a>.
        </p>
    </div>

    The script then just needs an if statement within the for loop that checks that this link should be included when processing:

    // Iterate through all anchors in the form
    for (var iCounter=0; iCounter<objAnchors.length; iCounter++)
    {
      // Only process anchors that link to the help section
      if (objAnchors[iCounter].className != 'leave')
      {
        // Locate the associated help text's container,
        // and hide it
        strID = getIDFromHref(objAnchors[iCounter].href);
        objHelp = document.getElementById(strID);
        objHelp.style.display = 'none';
    
        // Add events to reveal/hide
        objAnchors[iCounter].onclick = function(event){return expandHelp(this, event);}
        objAnchors[iCounter].onkeypress = function(event){return expandHelp(this, event);}
    
        // Move beneath current form field
        objAnchors[iCounter].parentNode.appendChild(objHelp);
      }
    }

    Posted by Gez on

  19. [form-help-without-popups.html#comment26]

    Very neat!

    Off-topic, I notice you used a relative path for your link to the example page. You might want to consider changing this, at least in the Atom feed; when I was reading the article at Bloglines I clicked on the link and got a 404 for www.bloglines.com/experiments/numbertransfer.php.

    Great article, though, as usual.

    Posted by Josh on

  20. [form-help-without-popups.html#comment27]

    Thank you for your kind words, Josh, and please accept my apologies for the delay in responding to your comment.

    Off-topic, I notice you used a relative path for your link to the example page. You might want to consider changing this, at least in the Atom feed; when I was reading the article at Bloglines I clicked on the link and got a 404 for www.bloglines.com/experiments/numbertransfer.php.

    The content element, which is the part displayed by news aggregators, contains an xml:base attribute whose value is a URI pointing to the original article on Juicy Studio. According to the draft Atom documentation, this attribute is to be interpreted according to Section 5.1 of RFC 3986. All relative links and fragment identifiers should be interpreted in relation to the the xml:base attribute.

    Having said that, I've recently received quite a few emails informing me that my Atom feed is broken because some news aggregators don't interpret the relative path correctly (all of them mention Bloglines, except one). On the one hand, I would like people to be able to read the feed without having to come over to the site to read the full article: on the other hand, pandering to broken user agents tends to perpetuate these types of problem, as it's the user agent that is broken, and not the feed.

    The other side of the argument is that I tend to write quite lengthy articles. I use minimal markup to keep the feed as light as possible, and adding the complete URI to every relative link (including fragment identifiers) is unnecessary bulk. I'm undecided about the best solution at this moment in time. With respect, as it's your user agent that is broken, I would appreciate it if you would kindly visit the website for any relative links for now, and I'll review the situation in a couple of months.

    Thank you again for your kind words.

    Best regards,

    Posted by Gez on

  21. [form-help-without-popups.html#comment28]

    Thanks for this script, I'm using it for a project I'm working on right now. However, one bug I found with it is that it doesn't check to see if the link actually does refer to an existing element, it seems to just assume that all links within the form will be help links and when it encounters one that isn't, it causes errors. Simple solution to fix this is to check if objHelp was set to anything:

    
    objHelp = document.getElementById(strID);
    if (objHelp) {
      objHelp.style.display = 'none';
    
      // Add events to reveal/hide
      objAnchors[iCounter].onclick = function(event){return expandHelp(this, event);}
      objAnchors[iCounter].onkeypress = function(event){return expandHelp(this, event);}
    
      // Move beneath current form field
      objAnchors[iCounter].parentNode.appendChild(objHelp);
    }
    

    Posted by Lachlan Hunt on

  22. [form-help-without-popups.html#comment30]

    Gez' solution and the proposed enhancements are technically elegant, but at some point they may run into usability problems because: (1) The help is downloaded even if the user doesn't need it; (2) The same help may be required on other pages (especially for a dynamically-generated e-commerce site), but it won't be cached.

    OK, the help in Gez' sample is a fairly small number of characters. But now imagine a site with a good search engine. The help on using search effectively often runs to a few A4 pages - a considerable overhead if it's loaded into every (dynamically-generated, un-cached) page and seldom actually used because casual visitors won't bother and regulars quickly learn as much as they (think they) need.

    How will screen readers react to the appearance and re-positioning of help text? My impression from Googling is that they vary a lot and that anything older than the 2005 version is likely to mess up dynamic content and / or fail to alert the user. So dynamic help may also have accessibility problems.

    I still feel that it's safer and in most respects more user friendly to provide a very short hint at the right place in the form, link the hint to the relevant section of the help page, and make the help open in a new window provided you warn the user that you will open a new window (this warning should at least appear in the link's TITLE).

    Posted by Philip Chalmers on

  23. [form-help-without-popups.html#comment31]

    Hi all,

    As this is a few years old, Gez has kindly allowed me to post a jQuery version of this which a colleague recently managed to get working.

    
    $(document).ready(addHelp);
    
    function addHelp()
    {
    	var strID, objHelp;
    	var $tooltips = $('div.tooltip a');
    	
    	$tooltips.click(function() {
    		var strID = $(this).attr('href');
    		var $helpContainer = $(strID);
    		$helpContainer.toggle();
    		return false;
        });
    	
    	$("#helpcontainer h2").css("display", "none");
    	$("#helpcontainer div").css("display", "none");
    	
    	$tooltips.each(function() {
    		var $parentFieldset = $(this).closest("fieldset");
    		var strID = $(this).attr('href');
    		var $helpContainer = $(strID);
    		$helpContainer.css("display", "none");
    		$helpContainer.appendTo($parentFieldset);
    	});
    }
    

    Hope this helps someone and like always, if it can be improved upn, please let us know.

    Many thanks,
    Jonathan

    Posted by Jonathan Thomas on

Comments are closed for this entry.