As part of a new UI library, I have put together an autocomplete feature using the jQuery UI Autocomplete in a manner that follows the guidelines found in the Webgrown Solutions UI Manifesto. The Autocomplete supports the following features:
A google search will be made on the person name selected.
Just a basic page <input type="text"> element, with a normal class attribute and some custom data (data-*) attributes to allow feature customization. Once the CSS and Script stuff are in place on a website, any page can implement the Autocomplete by simply setting the input element with the class attribute to "autocomplete", and setting the desired custom data attributes.
That sounds like a DRY solution to me (see UI Manifesto).
 
<h3>Simple Display, With No Highlighting</h3>
<p>
    <label for="txtAutocompleteDemo1">Person:</label> 
    <input type="text" id="txtAutocompleteDemo1" class="autocomplete"
        data-serviceRequestUrl="/WebServices/DemoClientService.svc/PersonAutocomplete1"
        data-serviceRequestDelay="300"
        data-serviceRequestMinLength="2"
        data-highlightMatches="false" />
</p>
<h3>Simple Display, With Highlighting</h3>
<p>
    <label for="txtAutocompleteDemo2">Person:</label> 
    <input type="text" id="txtAutocompleteDemo2" class="autocomplete"
        data-serviceRequestUrl="/WebServices/DemoClientService.svc/PersonAutocomplete1"
        data-serviceRequestDelay="300"
        data-serviceRequestMinLength="2"
        data-highlightMatches="true" />
</p>
<h3>Templated Display, With No Highlighting</h3>
<p>
    <script id="personTemplate" type="text/x-jquery-tmpl">
        <div class="itemName">${FullName}</div>
        <div class="itemDetails">${City}, ${StateAbbreviated} ${ZipCode}</div>
    </script>
    <label for="txtAutocompleteDemo3">Person:</label> 
    <input type="text" id="txtAutocompleteDemo3" class="autocomplete"
        data-serviceRequestUrl="/WebServices/DemoClientService.svc/PersonAutocomplete2"
        data-serviceRequestDelay="300"
        data-serviceRequestMinLength="2"
        data-itemTemplateId="personTemplate"
        data-propertyToUseOnSelect="FullName"
        data-highlightMatches="false" />
</p>
<h3>Templated Display, With Highlighting & Select Action</h3>
<p>A google search will be made on the person name selected.</p>
    <label for="txtAutocompleteDemo4">Person:</label> 
    <input type="text" id="txtAutocompleteDemo4" class="autocomplete"
        data-serviceRequestUrl="/WebServices/DemoClientService.svc/PersonAutocomplete2"
        data-serviceRequestDelay="300"
        data-serviceRequestMinLength="2"
        data-itemTemplateId="personTemplate"
        data-propertyToUseOnSelect="FullName"
        data-highlightMatches="true"
        data-selectActionFunction="googlePerson" />
</p>
//Enable Autocomplete(s)
lastErroredCallTrace += "->autocomplete";
$(parentElementSelector + " .autocomplete").each(function () {
    var tempThisVar = $(this);
    self.setTimeout(function () { enableFeature_Autocomplete(tempThisVar); }, 1);
});
function enableFeature_Autocomplete(targetElement) {
    lastErroredCallTrace += "->enableFeature_Autocomplete";
    //Check to see if already enabled.
    if (!isAttrDefined(targetElement.attr("data-autocompleteEnabled"))) {
        targetElement.autocomplete({
            //source: targetElement.attr("data-serviceRequestUrl"),
            source: function (request, response) {
                lastErroredFunctionName = "common.js -> $(parentElementSelector + .autocomplete).each(function () {";
                lastErroredRequestingElement = targetElement;
                lastErroredServiceRequestUrl = this.element.attr("data-serviceRequestUrl");
                lastErroredJsonToPost = "{ \"term\":\"" + request.term + "\"}";
                makesXhr = $.getJSON(this.element.attr("data-serviceRequestUrl"), { term: request.term }, function (data, textStatus, jqXHR) {
                    if (textStatus == "success") {
                        var dataTemp;
                        if (data.d == undefined) {
                            dataTemp = data;
                        }
                        else {
                            //WCF sends back with the dumb data.d as a string
                            dataTemp = $.trim(data.d);
                            dataTemp = $.parseJSON(dataTemp);
                        }
                        response(dataTemp);
                    }
                    else {
                        errorOnAjaxRequest(jqXHR, textStatus, "Error on Ajax Complete");
                    }
                });
            },
            open: function (event, ui) { if (!targetElement.is(":focus")) { targetElement.delay(500).autocomplete("close"); } },
            minLength: ((!isAttrDefined(targetElement.attr("data-serviceRequestMinLength")) || isNaN(targetElement.attr("data-serviceRequestMinLength"))) ? 2 : eval(targetElement.attr("data-serviceRequestMinLength"))),
            delay: ((!isAttrDefined(targetElement.attr("data-serviceRequestDelay")) || isNaN(targetElement.attr("data-serviceRequestDelay"))) ? 300 : eval(targetElement.attr("data-serviceRequestDelay"))),
            select: function (event, ui) {
                if (isAttrDefined(targetElement.attr("data-propertyToUseOnSelect")) && targetElement.attr("data-propertyToUseOnSelect").length > 0) {
                    targetElement.val(ui.item[targetElement.attr("data-propertyToUseOnSelect")]);
                }
                else {
                    targetElement.val(ui.item.value);
                }
                if (isAttrDefined(targetElement.attr("data-selectActionFunction")) && targetElement.attr("data-selectActionFunction").length > 0) {
                    callFunctionDynamically(targetElement.attr("data-selectActionFunction"), targetElement, ui.item);
                }
                return false;
            }
        })
            .data("autocomplete")._renderItem = function (ul, item) {
                if (isAttrDefined(this.element.attr("data-itemTemplateId")) && this.element.attr("data-itemTemplateId").length > 0) {
                    var itemTemplate = $("#" + this.element.attr("data-itemTemplateId")).html();
                    var itemVariables = itemTemplate.match(/\${([^}]*)}/gi); //Get "${...} vars.
                    for (x in itemVariables) {
                        if (x >= 0) {
                            var itemVariableFull = itemVariables[x];
                            var itemVariableNameOnly = itemVariableFull.substr(2, (itemVariableFull.length - 3));
                            var itemVariableValue = item[itemVariableNameOnly];
                            if (itemVariableValue != undefined && itemVariableValue.length > 0) {
                                if (this.element.attr("data-highlightMatches") == "true") {
                                    var regExp = new RegExp(this.term, "i");
                                    var match = regExp.exec(itemVariableValue);
                                    itemVariableValue = itemVariableValue.replace(regExp, markOpenTag + match + markCloseTag);
                                    itemTemplate = itemTemplate.replace(itemVariableFull, itemVariableValue);
                                }
                                else {
                                    itemTemplate = itemTemplate.replace(itemVariableFull, itemVariableValue);
                                }
                            }
                        }
                    }
                }
                else {
                    if (this.element.attr("data-highlightMatches") == "true") {
                        var regExp = new RegExp(this.term, "i");
                        var match = regExp.exec(item.label);
                        itemTemplate = item.label.replace(regExp, markOpenTag + match + markCloseTag);
                    }
                    else {
                        itemTemplate = item.label;
                    }
                }
                var anchorElement = document.createElement("a");
                anchorElement.className = "itemWrapper clearFix";
                anchorElement.innerHTML = itemTemplate;
                return $(liElementConstructor)
			    .data("item.autocomplete", item)
			    .append(anchorElement)
			    .appendTo(ul);
            };
        //Mark as enabled.
        targetElement.attr("data-autocompleteEnabled", true);
    }
}
 
/* General Autocomplete */
ul.ui-autocomplete li { border-top:1px dashed #CCC; }
ul.ui-autocomplete li:first-child { border-top-width:0px; }
ul.ui-autocomplete mark { background-color:Yellow; font-style:inherit; font-weight:inherit; }
/* Make Autocomplete Scrollable */
.ui-autocomplete { max-height:300px; overflow-y:auto; /* prevent horizontal scrollbar */ overflow-x:hidden; /* add padding to account for vertical scrollbar */ padding-right:20px; }
* html .ui-autocomplete { height:300px; }
<!-- The jQuery UI styling of your choice -->
<link href="jquery-ui.css" rel="stylesheet" type="text/css" />