AjaxPatterns
This is the original book draft version for the Suggestion Ajax pattern, offered for historical purposes and as an anti-spam measure.
You're probably better off visiting the Live Wiki Version for Suggestion instead, where you can make changes and see what others have written.

Suggestion

Auto-Complete, Fill, Intelligent, Populate, Predict, Suggest, Wizard

Goal Story

Doc is typing out an electronic prescription. He intends to prescribe "Vancomycin 65mg", but as soon as he types in "V", the system has already detected a handful of likely choices, based on the patient's history and Doc's prescription style. Doc selects "Vancomycin 65mg" from the list and proceeds to the next field.

Problem

How can you improve throughput?

Forces

  • Free text remains the most powerful way for humans to communicate with computers. The trend seems to be more typing than ever before, due to instant messaging, blogging, and email. Even search engines are undergoing a transformation to become general-purpose, as described in “Live Command-Line”.

  • When presented with a free text area, people don't always know what they're meant to type in.

  • Though many users are now quick on the keyboard, there are still many users for whom the web is a click-mostly experience.

  • Typing speed remains a bottleneck even for fast typists, most of whom think faster than they can type.

  • People make mistakes when they type.

Solution

Suggest words or phrases which are likely to complete what the user's typing. The user can then select the Suggestion and avoid typing it in full. The results usually come from an “XMLHttpRequest Call” - the partial input is uploaded and the server responds with a collection of likely matches.

Suggestion has its roots in "combo boxes" - fields on traditional GUI forms that combine a text input with a dropdown list. The elements are kept synchronised. The user is free to type any text, and the current selection in the list will track what's been typed so far. The user is also free to choose an element from the list, which will then be posted back to the text field. In some cases, the list constrains what the user types; in other cases, it's there to provide Suggestions only.

It's the latter style which has become popular in recent years - free text entry, with some Suggestions for completion at any time. Auto-completion became popular with Internet Explorer 5, which auto-completed fields based on user history. Most users will be comfortable with the approach, as all the modern browsers offer a similar feature, and the technique is also popular in mobile phone text messaging and East Asian text entry.

In an Ajaxian context, Google set the standard with its introduction of Google Suggest, which suggests the most popular terms that will complete the user's search query. Its release surprised many, as Google had managed to completely replicate conventional combo box behaviour, but this time, the terms were dynamically fetched from the server instead of being present when the form's created.

The mechanics of a Suggestion usually work like this:

  • A standard input field is used. At the same time, an initially-invisible div element is created to contain the Suggestions as they appear. The input field needs an event handler to monitor the text it contains, so as to ensure the list always highlights whichever Suggestion is matching.

  • Instead of requesting a Suggestion upon each keypress, “Submission Throttling” is usually adopted. Thus, every 100 milliseconds or so, the browser checks if anything changed since the last request. If so, the server is passed the partial query as an GET-based “XMLHttpRequest Call”.

  • The server then uses some algorithm to produce an ordered list of Suggestions.

  • Back in the browser, the callback function picks up the Suggestions and does some “Display Morphing” to show them to the user, in a format that allows them to be selected. Each entry will have an event handler, so that if clicked, the input field will be altered.

A combo-box is not the only way to render results, but it has the dual virtues of efficiency and familiarity. The Code Example below covers Kayak's implementation.

You might think the main benefit of a Suggestion is to cut down typing, but that's not the case. If anything, it's often slower to enter a single word using Suggestion as it's a distraction and probably requires some mousing. The main benefit is to offer a constrained set of choices - when there are more than would fit in an option list, but still a fixed set. For Google Suggest, it's a list of choices that are considered probable, based on search history. In tagging websites, it's a list of tag names that have been used in the past. In travel websites, it's a list of airports you can include on your ticket.

Decisions

What algorithm will be used to produce the Suggestions?

Ultimately, the Suggestion algorithm needs to find the most likely completions.

A few rules of thumb:

  • In general, historical data is the best predictor. Log what users are searching for, and use that as a basis for Suggestions. So when the user types "A", suggest the most frequent responses beginning with "A".

  • Personalise. Instead of completing "A" with the most common "A" query all users have entered, return the most common "A" queries for this user. The only problem here is lack of data, so consider a collaborative filtering algorithm to provide Suggestions based on similar users.

  • Recent history is a more pertinent guide, whether or not you're personalising the results. In some cases, it makes sense only to provide recent queries. In other cases, consider weighting recent results more heavily.

  • In some cases, it might make more sense for the browser to provide “Guesstimate”s rather than real results from the server in real-time. This information might be based on what's in a “Browser-Side Cache” and potentially a few algorithms to decide what's relevant.

How will the Suggestions be ordered?

Typical ordering algorithms include:

  • Estimated likelihood, e.g. historical frequency.

  • How recent the query was last used.

  • Alphabetical or numerical order.

  • Application-specific ordering. A currency list often begins with the US Dollar, for instance.

However you order your Suggestions, the first item is of particular importance because it can be designed so that the user is able to select the first element without explicitly choosing it from the list. For example, Google's combo-box implementation automatically inserts the first element in the text field, though with a text selection over the completion text, so the user can easily override it.

How many Suggestions will be shown?

Deciding how many Suggestions to show is a balancing act. You want to show enough Suggestions to be useful, but not so many that the good ones get lost in the crowd. Space is limited as well, even if you use a popup list.

It's generally useful if your Suggestion algorithm not only ranks Suggestions , but also makes a relevance estimate. Then, you can ensure Suggestions are shown only if they are particularly useful. Sometimes, it's not really worth showing any Suggestions.

What auxiliary information will be present with each Suggestion?

The core part of the Suggestion is always a word or phrase that completes what the user's typing. You can augment each Suggestion with supportive information. Google Suggest, for example, shows how many results each completion has. It would even be possible to present the Suggestions in a table, with several columns of background information per completion. Taken to an extreme, the Suggestion resembles a “Live Search”.

Real-World Examples

Kayak

Kayak is a travel search engine which suggests airports as you type in the locations (Figure 1.58, “Kayak Airport Suggestions”). The Suggestions appear in a combo-box format similar to Google Suggest.

Figure 1.58. Kayak Airport Suggestions

Kayak Airport Suggestions

Google Suggest

Google Suggest was probably the first public usage of Suggestion, and remains an excellent example. Results are shown in a combo-box style. The combo-box appearance is achieved with a custom control. A div is placed just under the text input, with a Suggestion on each row, and the zIndex property is used to make the div appear "in front of" the usual page content.

Delicious, Amazon

Delicious and Amazon both offer suggestions to help complete tags (Figure 1.59, “amazon tag suggestions”). As you type a tag, several suggestions appear immediately are populated below the field. You can click on a suggestion to complete the term.

Figure 1.59. amazon tag suggestions

amazon tag suggestions

Code Example [Kayak]

Kayak is a slick, Ajaxian, interface with a handy Suggestion feature for source and destination airports. The list of Suggestions appears below the input field, is referred to in the code as a "smartBox", and it exists so long as the input field has focus.

Whenever a key is pressed, the smartBox is aborted - which stops any pending request - and a new request is initiated. A check is made to ensure the text entry actually contains something, otherwise the smartBox is closed:

    function _typer(input)
      {
          if ((_input != null ) && _input.value.length > 0) {abortSmartBox();_runSearch(input);
}
          else {_setValue(-1);closeSmartBox();}
      }

_runSearch() kicks off a call to the server, to receive the Suggestion list. The query goes to http://www.kayak.com/m/smarty.jsp?where=LOCATION, with LOCATION being the location in the query. The result is some XML containing the airport names and codes and what appears to be an ID number, for example:

    <i>28501</i><m>L</m><d>London, United Kingdom</d><a>LON</a>

The callback function accumulates an HTML string to be inserted into the smartbox. A loop runs over each result, appending a div element to the HTML:

    var html = ""; var list = "";
    for (var j = 0; j < ii.length; j++) {
        var id=client.getTagText(results[0], "i", j);
        var str=client.getTagText(results[0], "d", j);
        var match=client.getTagText(results[0], "m", j);
        ...
        list += _divB + _spanB + icon + str + _spanE + _divE;cnt++;
    }

Also of interest is the optional icon, which appears beside the airport name, as the above code shows. Depending on the result XML, the icon is chosen from one of two images:

    var _iconAir = "<img style='vertical-align: middle' src='/images/airport_icon.gif' border=
'0'>";
    var _iconLoc = "<img style='vertical-align: middle; visibility: hidden' src=
'/images/place_icon.gif' border='0'>";
    ...
    icon = (match == "L") ? _iconLoc : _iconAir;

There is an event handler that monitors key presses. As the user moves up and down, the airport text is changed according to the selection and the selection incremented or decremented:

    case UP:
        _cursel--;if (_cursel<0){_cursel=0;}selChoice(_cursel);
    ...
    case DOWN:
        _cursel++;if (_cursel>=_ids.length){_cursel=_ids.length-1;}selChoice(_cursel);

Finally, the value is set when the user clicks tab or enter. In the former case, focus will also proceed to the next field:

    case ENTER:
        if (_ids.length>0){
            _setValue(_cursel);
            closeSmartBox();
        }
    ...
    case TAB:
        if (_cursel>=0&&_cursel<_ids.length){_setValue(_cursel);}

Alternatives

Selector

In some cases a plain old HTML selection input will suffice. Most modern browsers will support navigation through the dropdown with a keyboard, so it's an easy, viable, alternative if the range of inputs is constrained.

Related Patterns

A “Browser-Side Cache” is a practical way to speed up the search.

Sometimes the browser may be smart enough to derive Suggestions without resorting to the server. This would be an application of “Guesstimate”.

Suggestion is similar to “Predictive Fetch”. “Predictive Fetch” queries the server in anticipation of a future user action, whereas Suggestion queries the server to help the user complete the current action. In theory, you could actually combine the two patterns - perform a “Predictive Fetch” to pull down some Suggestions which might be needed in the future. On an intranet, for instance, it might be practical to continuously make 26 parallel queries, in anticipation of the user typing any letter of the alphabet.

To cut down on queries, don't issues an “XMLHttpRequest Call” upon every keypress. Instead, apply “Submission Throttling”, so calls are capped to a maximum frequency.

When one of the Suggestions in the list matches the free text input, it's usually a good idea to “Highlight” it.

“Lazy Registration” involves accumulation of profile information, and profiles can be used to generate personalised Suggestions. You might also retain user preferences regarding the appearance and timing of Suggestion lists.

When full result details are provided, Suggestion resembles a “Live Search”. However, the design goals are different and this should usually reflected in the user interface. A Suggestion is intended to complete a word or phrase; a “Live Search” is intended to locate or report on an item under search.

Want to Know More?

Acknowledgements

Chris Justus's thorough analysis of Google Suggest was very helpful in explaining the magic behind Google's Suggestion implementation.

Live Wiki Version for Suggestion