Hide Table of Contents
Search widget

This tutorial covers the following:

  1. Introduction to the Search widget
  2. Require modules
  3. Create an element in your HTML document to house the widget
  4. Specify a style to position the widget over the map and make the map fill the entire page
  5. Instantiate the widget
  6. Set a search extent
  7. Create a spotlight effect
  8. Putting it all together
  9. Bonus: Search using a feature layer
  1. Introduction to the Search widget

    Panning and zooming a map can be time consuming and a pain in your wrist. One way to provide easier map navigation is by adding a search box. A search box lets users to jump to a location quickly and easily.

    Now it is easier to add a search box that does just that by using the Search widget with the ArcGIS Global Geocoding service, your own custom geocoding service(s), and/or feature layer(s).

    View a live version of a sample that uses the Search widget in the ArcGIS API for JavaScript Sandbox. The sandbox is a live code editor that allows you to modify the sample's source and view the changes live.

    In this tutorial, you will add the Search widget to a basic map which allows your users to easily search for locations. Once added, we will go through a few customizations that can be applied to the Search widget.

  2. Require modules

    Require the widget and additional modules.

     require([
            "esri/map",
            "esri/dijit/Search",
            "esri/geometry/Extent",
            "esri/graphic",
            "esri/symbols/SimpleMarkerSymbol",
            "esri/geometry/screenUtils",
            "dojo/dom",
            "dojo/dom-construct",
            "dojo/query",
            "dojo/_base/Color",
            "dojo/domReady!"
          ], function (Map, Search, Extent, Graphic, SimpleMarkerSymbol, screenUtils, dom, domConstruct, query, Color) {
      // create a map and instance of the search widget here
    });
    

  3. Create an element in your HTML document to house the widget.

    <body>
      <div id="search"></div>
      <div id="map"></div>            
    </body>
    

  4. Specify a style to position the widget over the map and make the map fill the entire page.

    <style>
      html, 
      body, 
      #map {
        height: 100%;
        width: 100%;
        margin: 0;
        padding: 0;
      }
      #search {
        display: block;
        position: absolute;
        z-index: 3;
        top: 20px;
        left: 75px;
      }
    </style>
    

  5. Instantiate the widget

    Create a map and create an instance of the Search widget. As the second parameter to the Search constructor, pass a reference to the node where you want to attach the widget. This node already exists in our HTML document and has a an ID of "search". This sample specifies the minimum required Search parameters. After creating the widget, be sure to call startup().

        var map = new Map("map", {
          basemap: "topo", 
          center: [-117.19, 34.055], 
          zoom: 15
        });
    
        var search = new Search({
          map: map,
        }, dom.byId("search"));
    
        search.startup();
    

    At this point, we have the default Search widget in the page:

    The Search widget bases its search off of sources. These sources can be either geocoding service(s), or feature layer(s). Since nothing is specified, it automatically defaults to the ArcGIS Online World Geocoding service.

  6. Set a search extent

    The Search widget has additional capabilities such as constraining the search results to a specified extent. The widget's source has a searchExtent option which takes an array of extent objects. This option can be applied to both locators and feature layer sources. In this example, the search extent is set to a pre-defined extent that encompasses the City of Redlands and its surrounding area.

        var search = new Search({
           map: map
        }, "search");
      
        //Create extent to limit search
          var extent = new Extent({
             "spatialReference": {
                "wkid": 102100
                },
             "xmin": -13063280,
                "xmax": -13033928,
                "ymin": 4028345,
                "ymax": 4042715
             });
    
        //set the source's searchExtent to the extent specified above   
          search.sources[0].searchExtent = extent;
          
        //don't forget to start the widget
        search.startup();
    
  7. Create a spotlight effect

    The next couple of code snippets will add a spotlight effect which highlights the selected location.

    First, define the css styles that determine how the spotlight effect will look. Put the following inside an existing <style> tag:

    .spotlight {
      z-index:-1;
      position:absolute;
      left:50%;
      top:50%;
      border-radius:50%;
      opacity:0;
      box-shadow:
      inset rgba(0,0,0,0.25) 0px 0px 20px 20px,
      rgba(0,0,0,0.25) 0px 0px 0px 1000px;
      transition:all 1000ms;
      -moz-transition:all 1000ms;
      -webkit-transition:all 1000ms;
    }
    .spotlight-active {
      z-index:2;
      opacity:1;
    }
    

    Add code that adds a spotlight div to the map container once the map loads.

        map.on("load", enableSpotlight);
    
        function enableSpotlight() {
          var html = "<div id='spotlight' class='spotlight'></div>";
          domConstruct.place(html, dom.byId("map_container"), "first");
    }
    

    When a result is clicked or the enter key is pressed, add the spotlight to the map. Modify the showLocation function to be:

        function showLocation(e) {
          map.graphics.clear();
          var point = e.result.feature.geometry;
          var symbol = new SimpleMarkerSymbol().setStyle(
          SimpleMarkerSymbol.STYLE_SQUARE).setColor(
          new Color([255,0,0,0.5])
          );
          var graphic = new Graphic(point, symbol);
          map.graphics.add(graphic);
    
          map.infoWindow.setTitle("Search Result");
          map.infoWindow.setContent(e.result.name);
          map.infoWindow.show(e.result.feature.geometry);
    
          var spotlight = map.on("extent-change", function(extentChange) {
            var geom = screenUtils.toScreenGeometry(map.extent, map.width,    map.height, e.result.extent);
            var width = geom.xmax - geom.xmin;
            var height = geom.ymin - geom.ymax;
    
            var max = height;
            if ( width > height ) {
               max = width;
            }
    
            var margin = '-' + Math.floor(max/2) + 'px 0 0 -' + Math.floor(max/2) + 'px';
    
            query(".spotlight").addClass("spotlight-active").style({
              width: max + "px",
              height: max + "px",
              margin: margin
            });
            spotlight.remove();
          });
        }
    

    Finally, add logic to remove the spotlight when the search input is cleared.

        search.on("clear-search", removeSpotlight);
    
        function removeSpotlight() {
          query(".spotlight").removeClass("spotlight-active");
          map.infoWindow.hide();
          map.graphics.clear();
        }
    

    After adding the code above, the selected result has a spotlight effect:

  8. Putting it all together

    Complete spotlight example:

    <!DOCTYPE html>
    <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">
        <title>Search widget tutorial</title>
        <link rel="stylesheet" href="https://js.arcgis.com/3.20/esri/css/esri.css">
        <style>
          html, body, #map {
            height: 100%;
            width: 100%;
            margin: 0;
            padding: 0;
          }
          #search {
            display: block;
            position: absolute;
            z-index: 3;
            top: 20px;
            left: 75px;
          }
          .spotlight {
            z-index:-1;
            position:absolute;
            left:50%;
            top:50%;
            border-radius:50%;
            opacity:0;
            box-shadow:
            inset rgba(0,0,0,0.25) 0px 0px 20px 20px,
            rgba(0,0,0,0.25) 0px 0px 0px 1000px;
            transition:all 1000ms;
            -moz-transition:all 1000ms;
            -webkit-transition:all 1000ms;
          }
          .spotlight-active {
            z-index:2;
            opacity:1;
          }
        </style>
        
        <script src="https://js.arcgis.com/3.20/"></script>
        <script>
          require([
            "esri/map",
            "esri/dijit/Search",
            "esri/geometry/Extent",
            "esri/graphic",
            "esri/symbols/SimpleMarkerSymbol",
            "esri/geometry/screenUtils",
            "dojo/dom",
            "dojo/dom-construct",
            "dojo/query",
            "dojo/_base/Color",
            "dojo/domReady!"
          ], function(Map, Search, Extent, Graphic, SimpleMarkerSymbol, screenUtils, dom, domConstruct, query, Color) {
            // create a map and instance of the geocoder widget here
            var map = new Map("map", {
              basemap: "topo", 
              center: [-117.19, 34.055],
              zoom: 15
            });
    
             var search = new Search({
                map: map
             }, dom.byId("search"));
             
             //Create extent to limit search
             var extent = new Extent({
                "spatialReference": {
                   "wkid": 102100
                },
                "xmin": -13063280,
                "xmax": -13033928,
                "ymin": 4028345,
                "ymax": 4042715
             });
    
             //set the source's searchExtent to the extent specified above   
             search.sources[0].searchExtent = extent;
    
             //make sure to start up the widget!
             search.startup();
    
            map.on("load", enableSpotlight);
            search.on("select-result", showLocation); 
            search.on("clear-search", removeSpotlight);
    
            function showLocation(e) {
               map.graphics.clear();
               var point = e.result.feature.geometry;
               var symbol = new SimpleMarkerSymbol().setStyle(
               SimpleMarkerSymbol.STYLE_SQUARE).setColor(
                 new Color([255, 0, 0, 0.5])
               );
               var graphic = new Graphic(point, symbol);
               map.graphics.add(graphic);
    
               map.infoWindow.setTitle("Search Result");
               map.infoWindow.setContent(e.result.name);
               map.infoWindow.show(e.result.feature.geometry);
                
               var spotlight = map.on("extent-change", function () {
                  var geom = screenUtils.toScreenGeometry(map.extent,  map.width, map.height, e.result.extent);
                  var width = geom.xmax - geom.xmin;
                  var height = geom.ymin - geom.ymax;
    
                  var max = height;
                  if (width > height) {
                     max = width;
                  }
    
                  var margin = '-' + Math.floor(max / 2) + 'px 0 0 -' + Math.floor(max / 2) + 'px';
    
                  query(".spotlight").addClass("spotlight-active").style({
                     width: max + "px",
                     height: max + "px",
                     margin: margin
                  });
                  spotlight.remove();
                });
             }
    
            function enableSpotlight() {
              var html = "<div id='spotlight' class='spotlight'></div>"
              domConstruct.place(html, dom.byId("map_container"), "first");
            }
    
            function removeSpotlight() {
              query(".spotlight").removeClass("spotlight-active");
              map.infoWindow.hide();
              map.graphics.clear();
            }
          });
        </script>
      </head>
      <body>
        <div id="search"></div>
        <div id="map"></div>            
      </body> 
    </html>
    

  9. Bonus: Search using a feature layer

    The Search widget allows you to search fields in a feature layer to use along with or in place of a geocoder. In the following step, you first get a reference to the search's sources. After this, you will push a new source object back to it. This object can be either a locator or feature layer. In this specific case, we use a feature layer and provide additional properties to specify the field to search, how the suggestions should display (suggestionTemplate), in addition to a few other configurable settings.

        var sources = s.get("sources");
    
        sources.push({
           featureLayer: new   FeatureLayer("http://sampleserver6.arcgisonline.com/arcgis/rest/services/PhoneIncidents/MapServer/0"),
           searchFields: ["pocname"],
           suggestionTemplate: "${pocname}: ${synopsis}",
           exactMatch: false,
           name: "Redlands incidents",
           outFields: ["*"],
           placeholder: "Search for incidents",
           maxResults: 4,
           maxSuggestions: 3,
           enableSuggestions: true,
          minCharacters: 2
        });
      
        //Set the sources above to the search widget
        s.set("sources", sources);
        
    

    Additional Search samples are available in the Search category of the samples section of this site.