Developer Network Home - Help

Yahoo! UI Library: AutoComplete

AutoComplete

An example of the YUI AutoComplete Widget running on Yahoo! Finance.The AutoComplete control provides the front-end logic for text-entry suggestion and completion functionality. This control supports a variety of user interactions. See the Yahoo! UI Design Pattern Library description for AutoComplete to get a fuller sense of the underlying design patterns in the AutoComplete family. Using the YUI Library's AutoComplete control, a developer can implement these design patterns quickly and flexibly.

The AutoComplete control features navigation of the suggestion container via up/down arrow keys and a rich event model that gives you scriptological access to all of the interaction's interesting moments. Easily configurable parameters include custom formatting of AutoComplete suggestions, query delimiters (for multiple selections per input box), configurable query delay, type-ahead, animation of the suggestion container, built-in query caching, and much more.

Important Upgrade Note: As of the 2.3.0 release, in order to enable the new skinning model, AutoComplete now expects a wrapper DIV element around the INPUT element and the container DIV element, in this fashion:

    <div id="myAutoComplete">
        <input type="text" id="myInput">
        <div id="myContainer"></div>
    </div>

Getting Started

To use the AutoComplete control, include the following source files in your web page with the script tag:

YUI dependency configurator.

YUI Dependency Configurator:

Instead of copying and pasting the filepaths above, try letting the YUI dependency Configurator determine the optimal file list for your desired components; the Configurator uses YUI Loader write out the full HTML for including the precise files you need for your implementation.

Note: If you wish to include this component via the YUI Loader, its module name is autocomplete. (Click here for the full list of module names for YUI Loader.)

Where these files come from: The files included using the text above will be served from Yahoo! servers; see "Serving YUI Files from Yahoo!" for important information about this service. JavaScript files are minified, meaning that comments and white space have been removed to make them more efficient to download. To use the full, commented versions or the -debug versions of YUI JavaScript files, please download the library distribution and host the files on your own server.

Order matters: As is the case generally with JavaScript and CSS, order matters; these files should be included in the order specified above. If you include files in the wrong order, errors may result.

Using "CSS skins": One of the files listed above contains a CSS "skin" for the AutoComplete Control. For this skin CSS to work correctly, you will need to apply the CSS class "yui-skin-sam" to an element that is a parent of the element in which the component lives. You can usually accomplish this simply by putting the class on the <body> tag:

<body class="yui-skin-sam">

For more information on skinning YUI components and making use of default skins, see our Understanding YUI Skins article here on the website.

Your AutoComplete implementation will consist of two instantiated objects:

  • An AutoComplete object. Users interact directly with this object.
  • A DataSource object. The AutoComplete object interacts with the DataSource object to send queries and receive query result data. This DataSource needs to be YAHOO.widget.DataSource, which is packaged with AutoComplete, and not YAHOO.util.DataSource, which is available independently as the YUI DataSource Utility.

In addition to these two objects, you must also provide a data set and query logic to drive useful results to the user. Keep in mind that the quality of user's AutoComplete experience is highly dependent upon the quality of your data set and search logic.

Instantiating an AutoComplete Object

To create an AutoComplete instance on your page, use the following code:

The AutoComplete constructor has three required parameters:

  • the ID string or element reference to the input field (a textbox or textarea) where users will type queries
  • the ID string or element reference to the HTML container in which the query results will be displayed
  • the instance of the DataSource object that will query your data set and retrieve results (see the next section)

Instantiating a DataSource Object

Before you can instantiate an AutoComplete object, you must first instantiate a DataSource to pass in as the third parameter to the AutoComplete constructor. There are four subclasses of DataSource from which you may choose: DS_JSArray, DS_JSFunction, DS_XHR, and as of version 2.4.0, DS_ScriptNode. Which one you choose depends on the type of data you are using.

More details on the DataSource classes are contained in the section Using DataSources.

Using AutoComplete

The AutoComplete class provides many configuration parameters and a full portfolio of events that allow you to fine-tune the user experience of your AutoComplete instance. Configuration options include:

Animation

If you include the YUI Animation utility in your web page, you can enable animation on the transitions of the AutoComplete container element using the following code:

By default, if the Animation utility is present, the container will animate vertically, but not horizontally, over 0.3 seconds.

Delimiter Characters

By default, AutoComplete treats the user's input as a single string. Use the delimChar parameter to accept multiple delimited queries. Think about the way commas or semicolons are used to separate email addresses in an email application: enabling AutoComplete query delimiters is an easy way to help users address an email to multiple recipients in a single input box. By using delimChar to define an array of single characters, you may define more than one character that will delimit user queries. However, queries are not supported for when users are typing between existing delimited strings -- only the string after the last delimiter will be queried. Note: We do not recommend defining delimiter characters when the force selection feature (see below) is enabled, or vice versa.

Maximum Results Displayed

When query results return, an HTML unordered list element (<ul>) of up to ten items (<li> elements) are rendered into the container that you specify. If fewer than ten results are returned, the container's <ul> element will only have that number of <li> elements. Keep in mind that the height, width, and other style characteristics of the container are determined by CSS. You may use the following code to change the maximum number of <li> elements that may populate the <ul> element:

Minimum Query Length

By default, as soon as a user starts typing characters into the input element, the AutoComplete control starts batching characters for a query to the DataSource. You may increase how many characters the user must type before triggering this batching, which can help reduce load on a server, especially if the first few characters of the input string will not produce meaningful query results. A value of 0 will enable null or empty string queries, which is particularly useful in conjunction with the Always Show Container feature. A negative number value will effectively turn off the widget.

Query Delay

By default, AutoComplete batches user input and sends queries 0.2 seconds from the last key input event. You may adjust this delay for optimum user experience. Keep in mind that this value only reflects the delay before sending queries, and any delays in receiving query results that may be caused by server or computational latency will not be reflected in this value. In low-latency implementations (e.g., when queryDelay is set to 0 against a local JavaScript DataSource), typeAhead functionality (if enabled) may experience a race condition when retrieving the value of the textbox. Implementers are advised to bump up the queryDelay value artificially in this case to avoid this problem.

Auto-highlight

By default, when the container populates with query results, the first item in the list will be automatically highlighted for the user. Use the following code to disable this feature:

Highlight Class Name

By default, each <li> element of the container's <ul> element is assigned the class name yui-ac-highlight when it is selected. Style sheet examples have been provided for you in the AutoComplete examples . To customize the CSS of these elements, be sure to define a custom class and set the following configuration parameter:

Pre-highlight Class Name

If you would like to have user mouseover events on results list items trigger a different visual cue than arrow-key events, be sure to define a custom prehighlight class and set the following configuration parameter:

Use Shadow

If you would like the container element to have a drop-shadow, be sure to define a class yui-ac-shadow and enable the feature with the following code:

Use iFrame

An iFrame under the container element is meant to work around a known IE5.x and IE6 bug that causes form select elements to be displayed over elements with a higher z-index. If you would like the container element to have an iFrame shim, be sure to enable the feature for IE5.x and IE6 users with the following code:

Force Selection

You can enable the force-selection feature to require your users to select a result from the container, or else the input field is cleared of whatever they have typed. If the user types a string that does not match any query result, the input will be deleted from the field. Note: We do not recommend enabling the force-selection feature when delimChar is defined, or vice versa.

Type Ahead

Enabling the type-ahead feature causes the user's input to be automatically completed with the first query result in the container list. The string in the input field is also pre-selected, so it can be deleted as the user continues typing.

Allow Browser Autocomplete

Some browsers support a non-standard attribute on form elements called "autocomplete". When "autocomplete" is set to "on", the browser provides a built-in automatic completion mechanism — and it will cache the user input for automatic display if the user uses the "Back" button to navigate back to the page. In order for the YUI AutoComplete control to perform properly, the built-in browser completion mechanism needs to be suppressed. Therefore, the control sets the autocomplete attribute to "off" when the user starts typing in in an AutoComplete input field. However, the control will set the autocomplete attribute back to "on" if the form is submitted, so that a user's input can be displayed, should the "Back" button get clicked after form submission. This caching of user input may not be desired for sensitive data such as credit card numbers. Where you are dealing with sensitive user data, you should disable this feature with the following code:

Always Show Container

By default, the AutoComplete control shows the container when it is populated with query results and then hides it when the user interaction is complete. If you would like to always display the suggestion container, even when the user is not interacting directly with it, use the following code:

AutoComplete Custom Events

AutoComplete instances notify you of interesting moments via a set of Custom Events to which you can subscribe. The syntax for subscribing to AutoComplete events is simple; here's an example using itemSelectEvent, which gets passed an array argument (aArgs) containing the following members:

  • AutoComplete instance: a reference to the AutoComplete instance that is firing the event;
  • Element: a reference to the DOM list item element (LI) that has been selected in the container;
  • Data: an array containing the data associated with the selected item as returned by the DataSource.

For a full list of AutoComplete events, see the event list in the AutoComplete API documentation.

Using DataSources

The DataSource class represents databases of live data: where your data lives, how queries interact with your data, and the formatting of data returned to queries. At its core, a DataSource accepts strings as query values and returns a JavaScript array of matches. The DataSource class supports data that takes one of the following three forms:

  • JavaScript arrays
  • JavaScript functions
  • Server-side resources (such as PHP scripts, Java applications, or web services)
    • accessed via dynamically generated SCRIPT nodes
    • accessed via XMLHttpRequest connections

The nature of your data, its quantity, its complexity, and the logic for returning query results all play a role in determining your type of DataSource. For small amounts of simple textual data, a JavaScript array is a good choice. If your data has a small footprint but requires a simple computational or transformational filter before being displayed, a JavaScript function may be the right approach. For very large datasets — for example, a robust relational database — you'll certainly need to leverage the power of a Script Node or XHR DataSource and the data processing power that lives on the server side of your application.

Whatever choice is right for you, note that the DataSource class itself should not be instantiated. Rather, you should use one of its four subclasses to define your data source:

  • DS_JSArray defines a JavaScript array of strings.
  • DS_JSFunction defines a JavaScript function which returns a JavaScript array of strings.
  • DS_ScriptNode defines data sources that receive queries for JSON data via the Get Utility.
  • DS_XHR defines data sources that receive queries via Connection Manager.

Script Node and XHR types of DataSources are described in further detail in the section Working with Server-based DataSources. For more information on the differences between the Get Utility and Connection Manager, please refer to the documentation for the Get Utility.

DataSource Matching Algorithms

If you are working with a JSArray type of DataSource or have caching enabled on your DataSource (see Enabling DataSource Caching), please note two configurations that are available to you to fine-tune the matching algorithms applicable in these cases.

The parameter queryMatchCase enables case-sensitivity in the matching algorithm used against JSArray types of DataSources and DataSource caches. If queryMatchCase is true, only case-sensitive matches will return.

The parameter queryMatchCase causes the JSArray type of DataSource or DataSource cache (if enabled) to return results that "contain" the query string at any position. By default, queryMatchContains is set to false, so that only results that "start with" the query string are returned.

Enabling DataSource Caching

If round-trip queries to a live data source on a server are time- or resource-intensive, you can use the DataSource cache to store a simple JavaScript array of matches locally that have been returned from the live data source for a previous query. When a new query is triggered, the DataSource will first look in the cache, and if that query has already been made, then those cached results will be returned instead of hitting the live server. The query will only be forwarded to the live data source if there is no match found in the cache. By default, the size of the cache is 15 entries (in other words, results from 15 queries), but this can be easily adjusted with the configuration parameter below. Please note that there is no built-in limit to the number of results your DataSource can receive, so take care that your live data source doesn't return an unworkable volume of results.

Please note that there are cases where you will want to disable caching: perhaps query results become stale quickly, or perhaps query results depend on a dynamic or complex algorithm that exceeds the capabilities of the simple matching algorithms used by this JavaScript array-based cache. In order to disable caching on your DataSource object, use the following code:

Subset Caching

The subset cache can play an important role in achieving a robust and performant cache experience. When caching is enabled, the query for "foo" can get cached with 100 results. If subset matching is on, any query thereafter that starts with "foo" (e.g., "food" or "fool") goes first to the cache and retrieves results that are a subset of the 100 results that got cached for "foo". If subset caching is off, "foo" and "food" are cached separately and treated as independent entries. If your data universe is enormous (as is often the case in Yahoo! applications), you probably want to return the best 100 matches for "foo" and the best 100 matches for "food" separately. On much smaller datasets where the cached results for "foo" will reliably contain the superset of matches for the query "food", subset caching can reduce trips to the live data source and help improve performance. Note that even with subset caching enabled, if the cache returns no valid results, a query will be made to the live data source.

Working with Server-based DataSources

Server-based DataSources, namely DS_ScriptNode and DS_XHR, get their query results from a web application over HTTP. This section describes various aspects of working with server-based DataSources, including:

Indicating the URI of the Source

Since Script Node and XHR DataSources are used for data from online sources, you will need to provide a URI in the constructor of your DataSource instance. We assume that your online script or application will accept queries that look like this:

http://url?query=foo

Due to security-related limitations in XHR connections, you should be working with relative URIs and never with remotely located absolute URIs. When the server application is remote, you will need to set up a local proxy through which to traffic your requests to an XHR DataSource (for more information on this topic, please refer to the proxy HOWTO article at http://developer.yahoo.com/javascript/howto-proxy.html), or use a Script Node DataSource to leverage the proxyless cross-domain capabilities of the Get Utility.

Now let us suppose that we have a web server running a local proxy to a remote application. The queries will now look like this:

We will use the entire portion of the URI that occurs before the question mark (?) for the first argument of the DS_ScriptNode or DS_XHR constructor:

Understanding Data Types and Schemas

While DS_JSArray and DS_JSFunction instances return query results as JavaScript arrays, and DS_ScriptNode instances only work with JSON data, data output from DS_XHR instances can return data in one of three formats:

  • TYPE_JSON (default for DS_XHR)
  • TYPE_XML
  • TYPE_FLAT (i.e., comma-delimited, tab-delimited, etc.) (NOTE: In the current version of AutoComplete there is no notion of "escaping" delimiter characters — this is a limitation that may have a significant impact on flat-file implementations.)

You will need to define a schema to represent your server responses so that the DataSource can map data into a JavaScript array. These "translated" arrays of query results are what get stored in the cache (if enabled), get passed back to your AutoComplete instance for display to the user, and are available to you for custom formatting in the container (see below).

The DataSource schema is simply a JavaScript array of pointers to how your data is structured in your server responses. The array you define as your schema will need to have a specific syntax depending on the data type of your server response. In the next sections we'll show you example syntaxes for the different types of schema supported by DS_ScriptNode and DS_XHR.

Working with JSON for DS_ScriptNode or DS_XHR

Here is an example of some JSON data that may be returned by a server:

The first thing we do is figure out the object-notation path to a single result item. If result items are buried deep within the JSON structure, the path may be long, like "Root.Child.Child.Child.Result". In this example, results are found at "ResultSet.Result". Next, we find the key data field within each result object that queries will be matched against. Most likely this will be some sort of string data field that users are searching against, like "EmailAddress" or "SongTitle". In this example, users have been searching against titles, which is found in the member "Title" within each result. Finally, we determine if there are any other data fields within each result that we would like to work with, perhaps to show supplementary data to the user. In our example, we would like to link the titles to their corresponding URL and also display the modification date to the user. Therefore, we note that these fields are found in the members "Url" and "ModificationDate" within each result.

Now given these data pointers, we can place them into an array of the following syntax:

Here is the resultant schema that we now place into our DS_ScriptNode or DS_XHR constructor:

Working with XML for DS_XHR

Here is an example using the same data, only this time, it is returned by the server as XML:

The first thing we do is figure out the name of the node of a single result item. Even if result items are buried deep within the XML structure, we only need the node name. In this example, results are found at "Result". Next, we find the key data field within each result that queries will be matched against. Again, this will likely be some sort of string data field that users are searching against, like "EmailAddress" or "SongTitle". In this example, users have been searching against titles, which is found in the child node "Title" of each result node. Finally, we determine if there are any other data fields within each result that we would like to work with, perhaps to show supplementary data to the user. In our example, we would like to link the titles to their corresponding URL and also display the modification date to the user. Therefore, we note that these fields are found in the child nodes "Url" and "ModificationDate" within each result.

Now, given these data pointers, we can place them into an array of the following syntax. Please note that the syntax for the first item is somewhat different than the syntax for JSON data. This is due to the fundamental differences in the way JavaScript can parse the two different kinds of data.

Here is the resultant schema that we now place into our DS_XHR constructor:

Let's take a look at a slightly different type of XML server response. In this example, result data is not stored within child nodes of each result, but rather as attributes:

Revisiting our schema syntax, we see that attributes of nodes are not treated any differently than child nodes of nodes:

Here is a schema that we can use for this example, where the first item in the array is the node name of each result, the second item is the attribute name of the key data field within each result node, and we have picked four additional data fields to provide supplementary data to the user:

Working with Flat Data for DS_XHR

Now let's look at an example where the server is returning flat textual data. This type of data is frequently formatted with delimiters such as tabs and new lines, like this:

When using this relatively simple type of data structure, we must make a small set of assumptions:

  • There is a known and constant string delimiter of records.
  • Within each record, there is a known and constant string delimiter of data fields that is not equal to the record delimiter.
  • The key data field will always be the first data field returned for each record.
  • Data held in subsequent fields (if any) are available as supplemental data.
  • There are no escaped delimiter characters in the data

Now given these rules, we can create an array of the following syntax:

Here is the resultant schema that we now place into our DS_XHR constructor:

Configurations

There are a couple of configurations available to you to support the different ways that server-based data sources may receive queries. By default, Script Node and XHR DataSources work with queries that look like this:

http://url?query=foo

If your server requires queries to be sent with a different parameter name than the default "query", change the following configuration parameter:

If you would like to send additional parameters to your server, use the following configuration parameter to append any string of parameter/value pairs to each query request. Note that the first ampersand is automatically appended for you, so please do not prepend it to your string.

If your server appends each response with an HTML comment or other known string that may prevent successful parsing of the response by your DataSource, please set the following configuration parameter:

If you would like to set a timeout on the XHR connection so that the request is automatically aborted after the specified threshold (in milliseconds). Please note that this configuration property does not apply to Script Node DataSources.

Formatting Results

When query results are returned by the DataSource instance to the AutoComplete instance, the data is fed, one result at a time, into an AutoComplete instance method called formatResult. Most AutoComplete implementers override this method directly in their AutoComplete instance to achieve custom formatting. If you do this, start with the default formatResult method code to get started and make whatever changes you need.

For every successful query handled by your DataSource, each result item is put into an array and passed to the formatResult method as the first argument for HTML formatting. The string held in aResultItem[0] will always be the actual key data field returned for the query. All subsequent data held in aResultItem[1] to aResultItem[n] are the supplemental data points for the result, as defined by the schema in your DataSource constructor. Please note that if your implementation defines a JSON schema of length 2, then the entire result object literal will be available to the formatResult function as aResultItem[1]. The original query term is passed as a string to the formatResult method as the second argument.

Here's what the default formatResult method looks like:

Here's an example of a customized formatResult method that bolds the original query term and additionally displays two supplemental data points:

Skinning AutoComplete

AutoComplete comes with a default presentation or "skin," part of the "Sam Skin" visual treatment that accompanies most YUI controls. You can read more about the general approach to skinning YUI components in this in-depth article.

The CSS provided with AutoComplete is comprised of core, functional CSS as well as the Sam Skin visual treatment.

The AutoComplete Control

To explore the CSS which controls the AutoComplete's presentation, please review the AutoComplete Skinning Example wherein the full CSS for the control is displayed.

AutoComplete Storyboard Matrix

Storyboarding can be a powerful strategy for thinking through a rich interaction during the design phase. We have created a storyboard matrix for AutoComplete (also available as a .doc file) that helps you track the actors and the events that are important when a AutoComplete interaction is taking place. Interesting moments (which correspond to the API events to which you can subscribe handlers) are listed across the top; each row in the matrix represents an element. Consider printing out the matrix and using it in planning sessions between interaction architects and engineers as you think through the nuances of your implementation.

The AutoComplete storyboard matrix

Top Known Issues

Please see the bug repository at SourceForge for a complete list of known issues.

Bleed-through Scrollbars on Mac Firefox

Due to a known bug, the AutoComplete suggestion container may display underlying scrollbars.

Upgrading from version 0.11.4 or earlier

For implementers upgrading from version 0.11.4 or earlier, DataSource and DS_XHR constants have been converted from instance variables to static variables, and the following values should be updated as necessary:

  • Code that looks like myXHRDataSource.responseType = myXHRDataSource.TYPE_JSON;
    should be changed to myXHRDataSource.responseType = YAHOO.widget.DS_XHR.TYPE_JSON;
  • Code that looks like myXHRDataSource.responseType = myXHRDataSource.TYPE_XML;
    should be changed to myXHRDataSource.responseType = YAHOO.widget.DS_XHR.TYPE_XML;
  • Code that looks like myXHRDataSource.responseType = myXHRDataSource.TYPE_FLAT;
    should be changed to myXHRDataSource.responseType = YAHOO.widget.DS_XHR.TYPE_FLAT;
  • Any references to myXHRDataSource.ERROR_DATAXHR
    should be changed to YAHOO.widget.DS_XHR.ERROR_DATAXHR
  • Any references to myDataSource.ERROR_DATANULL
    should be changed to YAHOO.widget.DataSource.ERROR_DATANULL
  • Any references to myDataSource.ERROR_DATAPARSE
    should be changed to YAHOO.widget.DataSource.ERROR_DATAPARSE

YUI on Mobile: Using AutoComplete Control with "A-Grade" Mobile Browsers

About this Section: YUI generally works well with mobile browsers that are based on A-Grade browser foundations. For example, Nokia's N-series phones, including the N95, use a browser based on Webkit — the same foundation shared by Apple's Safari browser, which is found on the iPhone. The fundamental challenges in developing for this emerging class of full, A-Grade-derived browsers on handheld devices are:

  • Screen size: You have a much smaller canvas;
  • Input devices: Mobile devices generally do not have mouse input, and therefore are missing some or all mouse events (like mouseover);
  • Processor power: Mobile devices have slower processors that can more easily be saturated by JavaScript and DOM interactions — and processor usage affects things like battery life in ways that don't have analogues in desktop browsers;
  • Latency: Most mobile devices have a much higher latency on the network than do terrestrially networked PCs; this can make pages with many script, css or other types of external files load much more slowly.

There are other considerations, many of them device/browser specific (for example, current versions of the iPhone's Safari browser do not support Flash). The goal of these sections on YUI User's Guides is to provide you some preliminary insights about how specific components perform on this emerging class of mobile devices. Although we have not done exhaustive testing, and although these browsers are revving quickly and present a moving target, our goal is to provide some early, provisional advice to help you get started as you contemplate how your YUI-based application will render in the mobile world.

More Information:

We've tested the AutoComplete Control on several high-end smart phones with varying degrees of success. Due to high network latency, limited real estate, and inconsistent user interface models, the AutoComplete Control is not recommended as a good fit for these devices at this time.

Of the devices we've tested, the iPhone shows the most potential, and the following points are meant to give preliminary and cautionary guidance for developers implementing solely for that platform:

  • At this time, there is no known workaround to disable the native browser autocomplete attribute. Therefore, the native suggestion box may be redundantly displayed during user interactions with the AutoComplete control.
  • The typeahead feature is not supported.
  • High latency use cases are not recommended.
  • Designs should take into careful consideration the very limited screen real estate caused by the keyboard display. Before you implement, be sure to test this yourself on an iPhone or iPod Touch. While AutoComplete works on those devices, the keyboard placement and pagezoom hide the suggestion container almost completely.

Support & Community

The YUI Library and related topics are discussed on the on the ydn-javascript mailing list.

In addition, please visit the YUIBlog for updates and articles about the YUI Library written by the library's developers.

Filing Bugs & Feature Requests

The YUI Library's public bug tracking and feature request repositories are located on the YUI SourceForge project site. Before filing new feature requests or bug reports, please review our reporting guidelines.

Copyright © 2008 Yahoo! Inc. All rights reserved.

Privacy Policy - Terms of Service - Copyright Policy - Job Openings