Quickstart: Adding search to an app (HTML)

Most users rely on search to find what they're looking for. For example, if your app plays media files, users will expect to be able to search for a specific song or video; if your app is a cooking app, users will expect to search for specific recipes or ingredients.

With a little planning, it's not that difficult to add search to your app. Here's what you need:

  • A data source to search. You need some sort of catalog or inventory of items that users might want to search for. The more descriptive you can make this inventory, the better your search results will be.
  • A control for entering search queries. Windows provides a SearchBox control that your app can use. The SearchBox provides an input area for entering queries, a search button for executing the search, and events for handling search queries. It even provides some search suggestions automatically.
  • A page for displaying search results. Microsoft Visual Studio provides the Search Results Page template that creates a lot of the code you need to handle search queries and display results.

This quickstart tells you how to use these items to add search functionality to your app.

See this feature in action as part of our App features, start to finish series: Windows Store app UI, start to finish

Prerequisites

Set up your data

When the user enters a search query, your app searches for items that user might be looking for. The data your app searches could take several forms: it might be an XML file, JavaScript Object Notation (JSON) data, a database, a web service, or files in the file system.

The examples in this quickstart use the sample data that Microsoft Visual Studio generates when you create a new project in Visual Studio.

When you use Visual Studio to create a new Grid app, Hub app, or Split app, it creates a file named data.js in your app's js folder. This file includes static data that you can replace with your own data. For example, if your app makes a single xhr request to obtain RSS or JSON data, you might want to add your code to data.js. Including the code there enables you to easily use your own data without changing the data model used by the Search Results Page.

Here's an example of what the sample data looks like:

function generateSampleData() {
    // . . .
    var sampleGroups = [
        { key: "group1", title: "Group Title: 1", // . . .
        // . . .
    ];

    var sampleItems = [
        { group: sampleGroups[0], title: "Item Title: 1", // . . .
        // . . .
    ];

    return sampleItems;
}

To make this data accessible to your files, the data.js file defines a Data namespace that exposes these members:

  • items: A WinJS.Binding.List that contains the data items. This is a grouped List.
  • groups: A WinJS.Binding.List that contains the groups to which the data items belong. (You can also obtain the groups by calling items.groups.)
  • getItemReference: Retrieves an object that contains the group key and the title of the specified item.
  • getItemsFromGroup: Retrieves a FilteredListProjection that contains the items that belong to the group with the specified key.
  • resolveGroupReference: Retrieves an object that represents the group that has the specified key.
  • resolveItemReference: This method takes an array that contains two strings, a group key and title. This method retrieves the item that has the specified group key and title.

You don't have to use this namespace or these members to contain your data, but doing so will make it easier to use the Search Results Page template.

(For more info about working with the template-generated data, see How to customize Visual Studio template data.)

Add a Search Results page

The Search Results page processes search queries and displays the result. Let's add one to your project. (These instructions assume that your project was created from the Hub, Grid, or Split template. )

Hh465238.wedge(en-us,WIN.10).gifAdd the Search Results Page item

  1. In the pages project folder of Solution Explorer, add a new folder named search.

  2. Open the shortcut menu for the search folder, and then choose Add > New Item.

  3. In the center pane of the Add New Item dialog box, choose Search Results Page. For this example, keep the default name, searchResults.html, that appears in the Name box.

  4. Choose Add.

    Visual Studio adds searchResults.html, searchResults.css, and searchResults.js to the project in the new search folder.

We still have work to do on the search results page, but first, let's add a SearchBox to our app. Having a SearchBox will make it easier for us to test our search results page as we implement it.

A SearchBox lets the user enter queries. It can also display suggestions. To add a SearchBox to your app, just add this markup to an HTML page:

<div class="searchBox"
    data-win-control="WinJS.UI.SearchBox"
    data-win-options="{placeholderText: 'Search'}">
</div>

(You also need to register for the onquerysubmitted event; we'll do that in a later step.)

Where should you place your search box? We recommend putting a search box on each page of your app so users can easily search whenever they want to. If space is an issue, you can put the search box in a top app bar.

Hh465238.wedge(en-us,WIN.10).gifAdd a SearchBox to your page

  1. Let's add a SearchBox to one of your app's pages. These instructions will work for any page based on a Page control.

    Usually, the best location to put your SearchBox is in the upper-right corner of the page. Most pages that you create from a Visual Studio template (such as the Page Control template) have a header element that contains the page title and a back button:

            <header aria-label="Header content" role="banner">
                <button data-win-control="WinJS.UI.BackButton"></button>
                <h1 class="titlearea win-type-ellipsis">
                    <span class="pagetitle"></span>
                </h1>
            </header>
    

    Just add your SearchBox after the h1 element:

            <header aria-label="Header content" role="banner">
                <button data-win-control="WinJS.UI.BackButton"></button>
                <h1 class="titlearea win-type-ellipsis">
                    <span class="pagetitle">Welcome to basicPage</span>
                </h1>
                <div class="searchBox"
                     data-win-control="WinJS.UI.SearchBox"
                     data-win-options="{placeholderText: 'Search'}">
                </div>
            </header>
    
  2. (Recommended) You should give your users the ability to search for content in your app by simply beginning to type with their keyboard.

    Many people will use a keyboard to interact with Windows 8. Letting users search by typing makes efficient use of keyboard interaction and makes your app's search experience consistent with the Start screen.

    Set the SearchBox control's focusOnKeyboardInput property to true so that the search box receives input when a user types.

                <div class="searchBox"
                     data-win-control="WinJS.UI.SearchBox"
                     data-win-options="{placeholderText: 'Search',
                     focusOnKeyboardInput: true }">
                </div>
    
  3. The default.css style sheet that Visual Studio creates for you gives header elements an -ms-grid layout. To place your SearchBox in the upper-right corner of the page, just add this style to the Cascading Style Sheets (CSS) file for your page:

    .searchBox {
        -ms-grid-column: 4;
        margin-top: 57px;
        margin-right: 29px;
    }
    

Hh465238.wedge(en-us,WIN.10).gifHandle the onquerysubmitted event

  1. It's likely that your app will have multiple SearchBox controls. Let's define a single onquerysubmitted event handler that they can all use.

    Open your app's default.js file.

  2. Create an onquerysubmitted event handler named "querySubmittedHandler" that takes a single argument named "args". (You can put this method definition anywhere inside the anonymous function that wraps the existing default.js code.)

        function querySubmittedHandler(args) {
    
        }
    
  3. Use the event handler to navigate to your new search results page by calling WinJS.Navigation.navigate. The args.details property contains an object that provides info about the event that our search results page will need, so pass this object when you call WinJS.Navigation.navigate.

        function querySubmittedHandler(args) {
            WinJS.Navigation.navigate('/pages/search/searchResults.html', args.detail);
        }
    

    Warning  If you created your app using the Blank App template, you need to add navigation support to your app for search to work. You can support navigation the same way that the Grid, Split, and Navigation App templates do by adding a custom control called PageControlNavigator to your app. You can see how this custom control supports navigation in Quickstart: Using single-page navigation. If you'd rather support navigation without using a custom control, you have to write your own code that listens for and responds to navigation events like WinJS.Navigation.navigated. You can see an example of how to support navigation without using a custom control like PageControlNavigator in the Navigation and navigation history sample.

     

  4. Now we need to publicly expose this event handler by defining a namespace and making the handler a member. Let's call the namespace "SearchUtils". We also need to use the WinJS.UI.eventHandler method so we can set the event handler declaratively (for more info on how this works, see How to set event handlers declaratively).

        WinJS.Namespace.define("SearchUtils",
        {
            querySubmittedHandler: WinJS.UI.eventHandler(querySubmittedHandler)
        }
        );
    
  5. Open the HTML page that contains your SearchBox. Use the data-win-options property to set the onquerysubmitted event to SampleUtils.querySubmittedHandler.

                <div class="searchBox"
                     data-win-control="WinJS.UI.SearchBox"
                     data-win-options="{placeholderText: 'Search',
                     focusOnKeyboardInput: true,
                     onquerysubmitted: SearchUtils.querySubmittedHandler}">
                </div>
    

Let's try it out. Run the app and type a test query into the SearchBox and press Enter. If you're using the sample data provided by Visual Studio, try using "1" as your test query.

A test query

The onquerysubmitted event handler that you wrote navigates to the search results page, passing the query you entered.

Results of the test query

If you used the sample data, you should see matches for your test query. If you're using your own data, you might not get any results yet; we'll need to update the search results page first. We'll get to that in a later step.

Search your data

It's time to go back to our search results page. When your app navigates to the search results page, one of the first methods it calls is the _handleQuery method. The _handleQuery calls several methods that we should modify:

  1. _generateFilters

    Generates the list of filters that the user can click to filter results.

  2. _searchData

    Searches your data for matching items and stores them in a List named originalResults.

  3. _populateFilterBar

    Displays the filters in our filter list.

Let's update these methods to customize them for your data.

Update the filters

The _generateFilters method generates the list of filters that the user can click to filter results. The template-generated method creates three filters: an "All" filter for showing all results, a filter for showing the items in group 1, and a filter for showing everything else. Let's replace the template-generated code with code that generates the filter list dynamically. That way, if you change the sample data, your new filters will show up on the page. We'll update the _generateFilters code and create two helper methods. But first, we need to update our data.js file so that we can access the list of groups; we use these groups to define our filters.

Hh465238.wedge(en-us,WIN.10).gifUpdate the _generateFilters method

  1. In searchResults.js, find the _generateFilters method and delete the code it contains.

  2. Initialize the _filters array. (The _filters array is a member variable defined by the search results page.)

    
            _generateFilters: function () {
                this._filters = [];
    
  3. Now create a filter. A filter is an object that has three properties:

    • results: A List of the items to display. We'll set this to null for now.
    • text: The display text for the filter.
    • predicate: A function that takes an item. If the item meets the filter criteria (if it should be displayed when this filter is selected), this function returns true; otherwise, it returns false.

    First, let's create the "All" filter. The all filter always displays items, so its predicate always returns true.

    
                this._filters.push({ results: null, text: "All", predicate: function (item) { return true; } });
    
  4. Now lets create a filter for each group in our data. Our groups are stored as a List named Data.groups. Use the forEach method to iterate through each group in the List. The forEach method takes a function as its parameter; this function is called for each item in the list. Let's pass it a member function named _createFiltersForGroups; we'll create the function in the next step.

                if (window.Data) {
                    Data.groups.forEach(this._createFiltersForGroups.bind(this));
                }
            },
    
  5. Now let's create the _createFiltersForGroups function.

    1. Create a member function named _createFiltersForGroups that takes three parameters: element, index, and array.

              _createFiltersForGroups: function (element, index, array){
      
      
    2. The element parameter contains our group object. Create a new filter object and use the push method to add it to the _filters array. Set the filter's results property to null, its text property to element.title, and its predicate property to a function named _filterPredicate. You'll define the _filterPredicate method in the next step.

                  this._filters.push(
                      { results: null, text: element.title, predicate: this._filterPredicate.bind(element)}
                      );
              },
      
    3. Create a member function named _filterPredicate that takes a single parameter named item. Return true if the item parameter's group property is equal to the current group object.

              _filterPredicate: function (item) {
      
                  return item.group === this;          
              },
      

Here's the complete code for the three methods we just created:

        _generateFilters: function () {
            this._filters = [];
            this._filters.push({ results: null, text: "All", predicate: function (item) { return true; } });

            if (window.Data) {
                Data.groups.forEach(this._createFiltersForGroups.bind(this));
            }
        },

        _createFiltersForGroups: function (element, index, array){
            
            this._filters.push(
                { results: null, text: element.title, predicate: this._filterPredicate.bind(element)}
                );
        },

        _filterPredicate: function (item) {

            return item.group === this;          
        },

Run the app and perform a search; you should see your new filters in the filter bar.

The updated filters list

If you're using the template-generated sample data, you might notice that some of the groups are clipped. You can fix the issue by making a few adjustments to the CSS file for your search results page.

Hh465238.wedge(en-us,WIN.10).gifUpdate the CSS for the search results page

  1. Open searchResults.css.

  2. Find the .searchResults section[role=main] style and change the value of the -ms-grid-rows property to "auto 1fr".

    .searchResults section[role=main] {
        /* Define a grid with rows for the filters and results */
        -ms-grid-columns: 1fr;
        -ms-grid-rows: auto 1fr;
        -ms-grid-row: 1;
        -ms-grid-row-span: 2;
        display: -ms-grid;
    }
    
  3. Find the .searchResults section[role=main] .filterbar style and change the value of the word-wrap property to "normal" and set margin-bottom to "20px".

        .searchResults section[role=main] .filterbar {
            -ms-font-feature-settings: "case" 1;
            -ms-grid-row: 1;
            list-style-type: none;
            margin-left: 60px;
            margin-right: 60px;
            margin-top: 133px;
            max-width: calc(100% - 120px);
            position: relative;
            white-space: normal;
            z-index: 1; 
            margin-bottom: 20px; 
        }
    
  4. Find the .searchResults section[role=main] .filterbar li style and change the value of the display property to "inline-block".

            .searchResults section[role=main] .filterbar li {
                display: inline-block; 
                margin-left: 20px;
                margin-right: 20px;
                margin-top: 5px;
                opacity: 0.6;
            }
    
  5. Find the .searchResults section[role=main] .resultslist style and change the value of the -ms-grid-row property to "2" and set -ms-grid-row-span to "1".

        .searchResults section[role=main] .resultslist {
            -ms-grid-row: 2;
            -ms-grid-row-span: 1;
            height: 100%;
            position: relative;
            width: 100%;
            z-index: 0;
        }
    

Run the app and perform another search. You should see all of the filters now.

The updated filters list

Update the search algorithm

The _searchData method searches or data for items that match the search query. The template-generated code searches the title, subtitle, and description of each item. Let's write our own search code that ranks the results by relevancy.

Hh465238.wedge(en-us,WIN.10).gifUpdate the _searchData method

  1. Open searchResults.js, find the _searchData method, and delete the code it contains.

  2. Create a variable named originalResults; this will be our return value.

            // This function populates a WinJS.Binding.List with search results for the
            // provided query.
            _searchData: function (queryText) {
    
                // Create a variable for the results list.
                var originalResults;
    
  3. Let's make our search case-insensitive by converting both the query text and the text we're looking at to lowercase. Let's start by converting the query to lowercase and storing it as a variable named lowercaseQueryText.

                // Convert the query to lowercase. 
                var lowercaseQueryText = queryText.toLocaleLowerCase();
    
  4. Before we attempt to access our data, let's make sure the data exists.

                if (window.Data)
                {
    
  5. If you're using the sample data provided in data.js, then our items our stored in Data.items, a WinJS.Binding.List object. Use the createFiltered method to filter out items that don't satisfy the search query.

    The createFiltered method takes a filtering function as its parameter. This filtering function takes a single parameter, item. The List calls this function on each item in the list to determine whether it should be in the filtered list. The function returns true if the item should be included and false if it should be omitted.

                    originalResults = Data.items.createFiltered(
    
                        function (item) {
    
  6. In JavaScript, you can attach new properties to existing objects. Add a ranking property to item and set its value to "-1".

                            // A ranking < 0 means that a match wasn't found. 
                            item.ranking = -1;
    
  7. First, let's check to see whether the item's title contains the query text. If it does, give the item 10 points.

                            if (item.title.toLocaleLowerCase().indexOf(lowercaseQueryText) >= 0) {
    
                                item.ranking += 10;
                            }
    
  8. Next, let's check for hits in the subtitle field. If we find a match, give the item 5 points.

                            if (item.subtitle.toLocaleLowerCase().indexOf(lowercaseQueryText) >= 0) {
                                item.ranking += 5;
                            }
    
  9. Finally, let's check the description field. If we get a match, give the item 1 point.

                            if (item.description.toLocaleLowerCase().indexOf(lowercaseQueryText) >= 0) {
                                item.ranking += 1;
                            }
    
  10. If the item has a ranking of -1, that means it didn't match our search query. For our return value, return true if the item has a ranking of 0 or greater.

                            return (item.ranking >= 0);
                        }
                     );
    
  11. So far, we've filtered the list down to only the items that match the search query and we've added ranking info. Now let's use the createSorted method to sort our results list so that the items with the most points appear first.

                    // Sort the results by the ranking info we added. 
                    originalResults = originalResults.createSorted(function (firstItem, secondItem){
                            if (firstItem.ranking == secondItem.ranking) {
                                return 0;
                            }
                            else if (firstItem.ranking < secondItem.ranking)
                                return 1;
                            else
                                return -1;
                        });
    
                }
    
  12. If our data is missing, create an empty list.

                else {
    
                    // For some reason, the Data namespace is null, so we 
                    // create an empty list to return. 
                    originalResults = new WinJS.Binding.List();
    
                }
    
  13. Finally, return the results.

                return originalResults;
            }
    

Here's the complete code for the updated _searchData method.

        _searchData: function (queryText) {

            // Create a variable for the results list.
            var originalResults;

            // Convert the query to lowercase. 
            var lowercaseQueryText = queryText.toLocaleLowerCase();

            if (window.Data)
            {
                originalResults = Data.items.createFiltered(

                    function (item) {

                        // A ranking < 0 means that a match wasn't found. 
                        item.ranking = -1;

                        if (item.title.toLocaleLowerCase().indexOf(lowercaseQueryText) >= 0) {

                            item.ranking += 10;
                        }
                        if (item.subtitle.toLocaleLowerCase().indexOf(lowercaseQueryText) >= 0) {
                            item.ranking += 5;
                        }
                        if (item.description.toLocaleLowerCase().indexOf(lowercaseQueryText) >= 0) {
                            item.ranking += 1;
                        }

                        return (item.ranking >= 0);
                    }
                 );

                // Sort the results by the ranking info we added. 
                originalResults = originalResults.createSorted(function (firstItem, secondItem){
                        if (firstItem.ranking == secondItem.ranking) {
                            return 0;
                        }
                        else if (firstItem.ranking < secondItem.ranking)
                            return 1;
                        else
                            return -1;
                    });

            }
            else {

                // For some reason, the Data namespace is null, so we 
                // create an empty list to return. 
                originalResults = new WinJS.Binding.List();

            }

            return originalResults;
        }

When you run your app and perform a search, the search results page displays the results in a ListView control. Right now, clicking on one of these search result items doesn't do anything. Let's add some code to display the item when the user clicks it.

When the user clicks an item in a ListView, the ListView fires the oniteminvoked event. The template-generated code for our search results page defines an oniteminvoked event handler named _itemInvoked. Let's update the code to navigate to the invoked item.

Hh465238.wedge(en-us,WIN.10).gifTo add navigation to items

  • Open searchResults.js and add code to the _itemInvoked function to navigate to the correct page. Caution  The URI shown here is for the Hub template. For the Grid template, the URI must be: /pages/itemDetail/itemDetail.html. For the Split template, the URL must be: /pages/items/items.html.

     

            _itemInvoked: function (args) {
                args.detail.itemPromise.done(function itemInvoked(item) {
                    // TODO: Navigate to the item that was invoked.
                    var itemData = [item.groupKey, item.data.title];
                    WinJS.Navigation.navigate("/pages/item/item.html", { item: itemData });
                });
            },
    

(Optional) Update the ListView control's itemTemplate

The template-generated search results page defines an itemTemplate that is designed to work with the sample data source that Visual Studio creates for you; it expects the following fields in each data item: "image", "title", "subtitle", and "description".

If your data items have different fields, you need to modify the itemTemplate. For instructions, see Quickstart: Adding a ListView.

(Optional) Add search suggestions

Search suggestions are displayed under the search box in the search pane. Suggestions are important because they save users' time and give valuable hints about the kinds of things users can search for in your app.

You can get suggestions from several sources:

  • You can define them yourself. For example, you could create a list of car manufacturers.
  • You can get them from Windows if your app searches local files.
  • You can get them from a web service or server.

For user experience guidelines for displaying suggestions, see Guidelines and checklist for search.

You can use LocalContentSuggestionSettings to add suggestions, based on local files from Windows, in only a few lines of code. Alternatively, you can register for the search box control's onsuggestionsrequested event and build your own list of suggestions that is made up of suggestions you retrieved from another source (like a locally-defined list or a web service). This quickstart shows you how to handle the onsuggestionsrequested event.

For additional code examples that show how to add search suggestions, download the SearchBox control sample. The sample demonstrates how to add search suggestions by using all three possible sources, and how to add suggestions for East Asian languages by using alternate forms of the query text generated by an Input Method Editor (IME). (We recommend using query text alternatives if your app will be used by Japanese or Chinese users.)

Hh465238.wedge(en-us,WIN.10).gifHandle the SuggestionsRequested event

  1. It's likely that your app will have multiple SearchBox controls; let's define a single event handler in your default.js file that they can all use. Add this code after the querySubmittedHandler method that you created in an earlier step.

        function suggestionsRequestedHandler(args) {
    
  2. Convert the SearchBox query text to lowercase.

            var query = args.detail.queryText.toLocaleLowerCase();
    
  3. The system automatically provides some search suggestions, such as previous searches the user performed. Let's add our search suggestions to whatever the system provides.

            // Retrieve the system-supplied suggestions.
            var suggestionCollection = args.detail.searchSuggestionCollection;
    
  4. Verify that the query contains at least one character and that we have access to our data.

            if (query.length > 0 && window.Data) {
    
  5. Iterate through each item in your data and check for matches. When we find a match, append the matching item's title to the search suggestions collection.

                Data.items.forEach(
                    function (element, index, array) {
                        if (element.title.substr(0, query.length).toLocaleLowerCase() === query) {
                            suggestionCollection.appendQuerySuggestion(element.title);
                        }
    
                    });
    
  6. The args.detail.linguisticDetails.queryTextAlternatives property provides additional suggestions for users entering text in an IME. Using these suggestions improves the search experience for users of East Asian languages. Let's check the query text alternatives for strings that contain the original query and add them to our search suggestion list.

                args.detail.linguisticDetails.queryTextAlternatives.forEach(
                    function (element, index, array) {
                        if (element.substr(0, query.length).toLocaleLowerCase() === query) {
                            suggestionCollection.appendQuerySuggestion(element);
                        }
    
                    });
            }
        }
    

    That's all the code we need for our search suggestion event handler. Here's the complete suggestionsRequestedHandler method:

        function suggestionsRequestedHandler(args) {
    
            var query = args.detail.queryText.toLocaleLowerCase();
    
            // Retrieve the system-supplied suggestions.
            var suggestionCollection = args.detail.searchSuggestionCollection;
    
            if (query.length > 0 && window.Data) {
    
                Data.items.forEach(
                    function (element, index, array) {
                        if (element.title.substr(0, query.length).toLocaleLowerCase() === query) {
                            suggestionCollection.appendQuerySuggestion(element.title);
                        }
    
                    });
    
                args.detail.linguisticDetails.queryTextAlternatives.forEach(
                    function (element, index, array) {
                        if (element.substr(0, query.length).toLocaleLowerCase() === query) {
                            suggestionCollection.appendQuerySuggestion(element);
                        }
    
                    });
    
            }
        }
    

    Note  If your data source is asynchronous, you must wrap updates to the search suggestion collection in a Promise. The sample code uses a List, which is a synchronous data source, but here's what the method would look like if the List were an asynchronous data source.

     

        function suggestionsRequestedHandler(args) {
    
            var query = args.detail.queryText.toLocaleLowerCase();
    
            // Retrieve the system-supplied suggestions.
            var suggestionCollection = args.detail.searchSuggestionCollection;
    
            if (query.length > 0 && window.Data) {
    
                args.detail.setPromise(WinJS.Promise.then(null, 
                    function () {
                        Data.items.forEach(
                            function (element, index, array) {
                                if (element.title.substr(0, query.length).toLocaleLowerCase() === query) {
                                    suggestionCollection.appendQuerySuggestion(element.title);
                                }
    
                            });
    
                        args.detail.linguisticDetails.queryTextAlternatives.forEach(
                            function (element, index, array) {
                                if (element.substr(0, query.length).toLocaleLowerCase() === query) {
                                    suggestionCollection.appendQuerySuggestion(element);
                                }
    
                            });
    
                    })
                 );
            }
        }
    
  7. That's all the code we need for our search suggestion event handler. Let's make it publicly accessible by exposing it through the SearchUtils namespace we defined in an earlier step:

        WinJS.Namespace.define("SearchUtils",
        {
            querySubmittedHandler: WinJS.UI.eventHandler(querySubmittedHandler),
            suggestionsRequestedHandler: WinJS.UI.eventHandler(suggestionsRequestedHandler)
        }
        );
    
  8. Now let's register the event with our SearchBox. Open the HTML page that contains your SearchBox and set the onsuggestionsrequested event to SearchUtils.suggestionsRequestedHandler.

                <div class="searchBox"
                     data-win-control="WinJS.UI.SearchBox"
                     data-win-options="{placeholderText: 'Search',
                     focusOnKeyboardInput: true,
                     onquerysubmitted: SearchUtils.querySubmittedHandler,
                     onsuggestionsrequested: SearchUtils.suggestionsRequestedHandler}">
                </div>
    

Implementing the Search contract (for previous versions of Windows)

Prior to Windows 8.1, apps used the Search charm to provide in-app search. Developers implemented the Search contract and used the SearchPane API to handle queries and obtain suggestions and results.

Although we continue to fully support the Windows 8 Search contract and the SearchPane API, as of Windows 8.1, we recommend using the SearchBox control instead of the SearchPane. Apps that use the SearchBox don't need to implement the Search contract.

Should an app ever use the SearchPane and Search contract? If you don't expect users to search your app very much, you can use the SearchPane and Search contract. We recommend that you use a button with the Search glyph (Segoe UI Symbol 0xE0094 at 15pt) in your app that users can click to activate the search pane. To see code that implements the SearchPane and the Search contract, see the Search contract sample.

Summary and next steps

You used the SearchBox control and the Search Results Page to add search to your app.

For guidelines to help you design and create a good search experience for your users, see Guidelines and checklist for search.

SearchBox control sample

Guidelines and checklist for search