[MD Extensions] Move search field out of downloads, use it in extensions

Make the search-field element a web component, and move it to ui/webui/. Use
it in the MD extensions page, and add a toolbar.

BUG=529395

Review URL: https://codereview.chromium.org/1308893009

Cr-Commit-Position: refs/heads/master@{#349260}
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index ef334bab..80dbccf 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -4713,6 +4713,12 @@
         <message name="IDS_EXTENSIONS_SHOW_BUTTON" desc="The text for the Show link.">
           Show button
         </message>
+        <message name="IDS_MD_EXTENSIONS_TOOLBAR_TITLE" desc="The text displayed in the toolbar of the chrome://extensions page.">
+          Extensions &amp; Apps
+        </message>
+        <message name="IDS_MD_EXTENSIONS_SEARCH" desc="The text displayed in the search box on the chrome://extensions page.">
+          Search
+        </message>
         <if expr="not use_titlecase">
           <message name="IDS_EXTENSIONS_ALWAYS_RUN" desc="The text for the 'always run' item in context menus (sentence case).">
             Always run
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index 91415cc..31f7584 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -146,8 +146,12 @@
         <include name="IDR_EXTENSION_COMMAND_LIST_JS" file="resources\extensions\extension_command_list.js" flattenhtml="true" type="BINDATA" />
         <include name="IDR_EXTENSION_LIST_JS" file="resources\extensions\extension_list.js" flattenhtml="true" type="BINDATA" />
         <include name="IDR_EXTENSIONS_JS" file="resources\extensions\extensions.js" flattenhtml="true" type="BINDATA" />
+        <include name="IDR_MD_EXTENSIONS_MANAGER_CSS" file="resources\md_extensions\manager.css" type="BINDATA" />
         <include name="IDR_MD_EXTENSIONS_MANAGER_HTML" file="resources\md_extensions\manager.html" type="BINDATA" />
         <include name="IDR_MD_EXTENSIONS_MANAGER_JS" file="resources\md_extensions\manager.js" type="BINDATA" />
+        <include name="IDR_MD_EXTENSIONS_TOOLBAR_CSS" file="resources\md_extensions\toolbar.css" type="BINDATA" />
+        <include name="IDR_MD_EXTENSIONS_TOOLBAR_HTML" file="resources\md_extensions\toolbar.html" type="BINDATA" />
+        <include name="IDR_MD_EXTENSIONS_TOOLBAR_JS" file="resources\md_extensions\toolbar.js" type="BINDATA" />
         <include name="IDR_MD_EXTENSIONS_STRINGS_HTML" file="resources\md_extensions\strings.html" type="BINDATA" />
       </if>
       <include name="IDR_FEEDBACK_MANIFEST" file="resources\feedback\manifest.json" type="BINDATA" />
diff --git a/chrome/browser/resources/md_downloads/compiled_resources.gyp b/chrome/browser/resources/md_downloads/compiled_resources.gyp
index 934ec36..8419de4 100644
--- a/chrome/browser/resources/md_downloads/compiled_resources.gyp
+++ b/chrome/browser/resources/md_downloads/compiled_resources.gyp
@@ -7,6 +7,7 @@
       'target_name': 'manager',
       'variables': {
         'depends': [
+          '../../../../ui/webui/resources/cr_elements/v1_0/cr_search_field/cr_search_field.js',
           '../../../../ui/webui/resources/js/action_link.js',
           '../../../../ui/webui/resources/js/assert.js',
           '../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
diff --git a/chrome/browser/resources/md_downloads/toolbar.css b/chrome/browser/resources/md_downloads/toolbar.css
index 3613c86..4dbd506d 100644
--- a/chrome/browser/resources/md_downloads/toolbar.css
+++ b/chrome/browser/resources/md_downloads/toolbar.css
@@ -11,11 +11,6 @@
   height: 56px;
 }
 
-#title,
-#search {
-  flex: 1 0 var(--downloads-side-column-basis);
-}
-
 #title h1 {
   -webkit-margin-end: 0;
   -webkit-margin-start: 24px;
@@ -39,8 +34,7 @@
   -webkit-margin-end: 8px;
 }
 
-#actions,
-#search-term {
+#actions {
   color: rgb(192, 199, 205);
 }
 
@@ -51,34 +45,9 @@
   justify-content: flex-end;
 }
 
-#search paper-input-container {
-  margin-top: 2px;
-  max-width: 200px;
-  padding: 2px 0;
-  width: 100%;
-}
-
-#search-term {
-  --paper-input-container-color: rgb(192, 199, 205);
-  --paper-input-container-focus-color: rgb(192, 199, 205);
-  --paper-input-container-input: {
-    color: inherit;
-    font-family: inherit;
-    font-size: inherit;
-  };
-  --paper-input-container-input-color: rgb(192, 199, 205);
-  z-index: 0;
-}
-
-#search-term input[type='search']::-webkit-search-decoration,
-#search-term input[type='search']::-webkit-search-cancel-button,
-#search-term input[type='search']::-webkit-search-results-button {
-  -webkit-appearance: none;
-}
-
-#search-term input[type='search']::-webkit-search-cancel-button {
-  display: block;
-  width: 20px;
+#title,
+#search {
+  flex: 1 0 var(--downloads-side-column-basis);
 }
 
 paper-icon-button {
@@ -91,26 +60,6 @@
   };
 }
 
-#search-term paper-icon-button {
-  --iron-icon-height: 16px;
-  --iron-icon-width: 16px;
-  --paper-icon-button: {
-    -webkit-margin-end: -8px;
-    height: 16px;
-    padding: 8px;
-    width: 16px;
-  };
-  position: absolute;
-  right: 0;
-  top: -4px;
-  z-index: 1;
-}
-
-:host-context([dir='rtl']) #search-term paper-icon-button {
-  left: 0;
-  right: auto;
-}
-
 #more {
   --paper-menu-button: {
     padding: 0;
diff --git a/chrome/browser/resources/md_downloads/toolbar.html b/chrome/browser/resources/md_downloads/toolbar.html
index c1814dee..dedddc8 100644
--- a/chrome/browser/resources/md_downloads/toolbar.html
+++ b/chrome/browser/resources/md_downloads/toolbar.html
@@ -1,12 +1,11 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/iron-icons.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-input/iron-input.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input-container.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-item/paper-item.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-menu/paper-menu.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-menu-button/paper-menu-button.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html">
+<link rel="import" href="chrome://resources/cr_elements/v1_0/cr_search_field/cr_search_field.html">
 <link rel="import" href="chrome://resources/html/assert.html">
 <link rel="import" href="chrome://resources/html/cr.html">
 
@@ -22,18 +21,7 @@
           on-click="onOpenDownloadsFolderClick_"></paper-button>
     </div>
     <div id="search">
-      <paper-icon-button icon="search" id="search-button"
-          i18n-values="title:search"
-          on-click="toggleShowingSearch_"></paper-icon-button>
-      <paper-input-container id="search-term" on-search="onSearchTermSearch_"
-          on-keydown="onSearchTermKeydown_" hidden$="[[!showingSearch_]]"
-          no-label-float>
-        <input is="iron-input" id="search-input" type="search"
-            i18n-values="placeholder:search" incremental>
-        <paper-icon-button icon="cancel" id="clear-search"
-            on-click="toggleShowingSearch_"
-            hidden$="[[!showingSearch_]]"></paper-icon-button>
-      </paper-input-container>
+      <cr-search-field id="search-input"></cr-search-field>
       <paper-menu-button id="more" horizontal-align="right">
         <paper-icon-button icon="more-vert" i18n-values="title:moreActions"
              class="dropdown-trigger"></paper-icon-button>
diff --git a/chrome/browser/resources/md_downloads/toolbar.js b/chrome/browser/resources/md_downloads/toolbar.js
index 0611152..3cab91f 100644
--- a/chrome/browser/resources/md_downloads/toolbar.js
+++ b/chrome/browser/resources/md_downloads/toolbar.js
@@ -12,6 +12,12 @@
       this.actionService_ = actionService;
     },
 
+    attached: function() {
+      /** @private {!SearchFieldDelegate} */
+      this.searchFieldDelegate_ = new ToolbarSearchFieldDelegate(this);
+      this.$['search-input'].setDelegate(this.searchFieldDelegate_);
+    },
+
     properties: {
       downloadsShowing: {
         reflectToAttribute: true,
@@ -19,11 +25,6 @@
         value: false,
         observer: 'onDownloadsShowingChange_',
       },
-
-      showingSearch_: {
-        type: Boolean,
-        value: false,
-      },
     },
 
     /** @return {boolean} Whether removal can be undone. */
@@ -33,7 +34,7 @@
 
     /** @return {boolean} Whether "Clear all" should be allowed. */
     canClearAll: function() {
-      return !this.$['search-input'].value && this.downloadsShowing;
+      return !this.$['search-input'].getValue() && this.downloadsShowing;
     },
 
     /** @private */
@@ -47,44 +48,42 @@
       this.updateClearAll_();
     },
 
-    /** @private */
-    onSearchTermSearch_: function() {
-      this.actionService_.search(this.$['search-input'].value);
+    /** @param {string} searchTerm */
+    onSearchTermSearch: function(searchTerm) {
+      this.actionService_.search(searchTerm);
       this.updateClearAll_();
     },
 
     /** @private */
-    onSearchTermKeydown_: function(e) {
-      assert(this.showingSearch_);
-      if (e.keyIdentifier == 'U+001B')  // Escape.
-        this.toggleShowingSearch_();
-    },
-
-    /** @private */
     onOpenDownloadsFolderClick_: function() {
       this.actionService_.openDownloadsFolder();
     },
 
     /** @private */
-    toggleShowingSearch_: function() {
-      this.showingSearch_ = !this.showingSearch_;
-      this.$['search-button'].disabled = this.showingSearch_;
-
-      if (this.showingSearch_) {
-        this.$['search-input'].focus();
-      } else {
-        this.$['search-input'].value = '';
-        this.onSearchTermSearch_();
-      }
-    },
-
-    /** @private */
     updateClearAll_: function() {
       this.$$('#actions .clear-all').hidden = !this.canClearAll();
       this.$$('paper-menu .clear-all').hidden = !this.canClearAll();
     },
   });
 
+  /**
+   * @constructor
+   * @implements {SearchFieldDelegate}
+   */
+  // TODO(devlin): This is a bit excessive, and it would be better to just have
+  // Toolbar implement SearchFieldDelegate. But for now, we don't know how to
+  // make that happen with closure compiler.
+  function ToolbarSearchFieldDelegate(toolbar) {
+    this.toolbar_ = toolbar;
+  }
+
+  ToolbarSearchFieldDelegate.prototype = {
+    /** @override */
+    onSearchTermSearch: function(searchTerm) {
+      this.toolbar_.onSearchTermSearch(searchTerm);
+    }
+  };
+
   return {Toolbar: Toolbar};
 });
 
diff --git a/chrome/browser/resources/md_extensions/compiled_resources.gyp b/chrome/browser/resources/md_extensions/compiled_resources.gyp
index 467b8cc..2b001ed2 100644
--- a/chrome/browser/resources/md_extensions/compiled_resources.gyp
+++ b/chrome/browser/resources/md_extensions/compiled_resources.gyp
@@ -7,6 +7,8 @@
       'target_name': 'manager',
       'variables': {
         'depends': [
+          '../../../../ui/webui/resources/cr_elements/v1_0/cr_search_field/cr_search_field.js',
+          '../../../../ui/webui/resources/js/assert.js',
           '../../../../ui/webui/resources/js/cr.js',
         ],
         'externs': [
diff --git a/chrome/browser/resources/md_extensions/extensions.html b/chrome/browser/resources/md_extensions/extensions.html
index bd27846..bca5f8b 100644
--- a/chrome/browser/resources/md_extensions/extensions.html
+++ b/chrome/browser/resources/md_extensions/extensions.html
@@ -11,6 +11,7 @@
     }
     html,
     body {
+      font-family: Roboto;
       height: 100%;
       margin: 0;
     }
diff --git a/chrome/browser/resources/md_extensions/manager.css b/chrome/browser/resources/md_extensions/manager.css
new file mode 100644
index 0000000..999634de
--- /dev/null
+++ b/chrome/browser/resources/md_extensions/manager.css
@@ -0,0 +1,13 @@
+/* Copyright 2015 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+:host {
+  height: 100%;
+}
+
+#panel {
+  --paper-header-panel-standard-container: {
+    display: flex;
+  };
+}
diff --git a/chrome/browser/resources/md_extensions/manager.html b/chrome/browser/resources/md_extensions/manager.html
index a72c183..9ec0e1f 100644
--- a/chrome/browser/resources/md_extensions/manager.html
+++ b/chrome/browser/resources/md_extensions/manager.html
@@ -1,6 +1,15 @@
 <link rel="import" href="chrome://resources/html/cr.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-header-panel/paper-header-panel.html">
+<link rel="import" href="chrome://extensions/toolbar.html">
 
 <dom-module id="extensions-manager">
+  <template>
+    <paper-header-panel id="panel">
+      <extensions-toolbar class="paper-header" id="toolbar">
+      </extensions-toolbar>
+    </paper-header-panel>
+  </template>
+  <link rel="import" type="css" href="chrome://extensions/manager.css">
   <script src="chrome://extensions/manager.js"></script>
 </dom-module>
diff --git a/chrome/browser/resources/md_extensions/toolbar.css b/chrome/browser/resources/md_extensions/toolbar.css
new file mode 100644
index 0000000..396d29e
--- /dev/null
+++ b/chrome/browser/resources/md_extensions/toolbar.css
@@ -0,0 +1,24 @@
+/* Copyright 2015 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+:host {
+  align-items: center;
+  background: rgb(63, 85, 102);
+  color: white;
+  display: flex;
+  height: 56px;
+}
+
+#search-field {
+  -webkit-padding-end: 10px;
+}
+
+#title {
+  -webkit-margin-start: 24px;
+  flex: 1;
+  font-size: 107.7%;
+  font-weight: normal;
+  margin-bottom: 0;
+  margin-top: 0;
+}
diff --git a/chrome/browser/resources/md_extensions/toolbar.html b/chrome/browser/resources/md_extensions/toolbar.html
new file mode 100644
index 0000000..0a3da81
--- /dev/null
+++ b/chrome/browser/resources/md_extensions/toolbar.html
@@ -0,0 +1,12 @@
+<link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/cr_elements/v1_0/cr_search_field/cr_search_field.html">
+
+<dom-module id="extensions-toolbar">
+  <template>
+    <h1 i18n-content="toolbarTitle" id="title"></h1>
+    <cr-search-field id="search-field"></cr-search-field>
+  </template>
+  <link rel="import" type="css" href="chrome://extensions/toolbar.css">
+  <script src="chrome://extensions/toolbar.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/md_extensions/toolbar.js b/chrome/browser/resources/md_extensions/toolbar.js
new file mode 100644
index 0000000..fade7d41
--- /dev/null
+++ b/chrome/browser/resources/md_extensions/toolbar.js
@@ -0,0 +1,33 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+cr.define('extensions', function() {
+  var Toolbar = Polymer({
+    is: 'extensions-toolbar',
+
+    /** @param {string} searchTerm */
+    onSearchTermSearch: function(searchTerm) {
+    },
+  });
+
+  /**
+   * @constructor
+   * @implements {SearchFieldDelegate}
+   */
+  // TODO(devlin): This is a bit excessive, and it would be better to just have
+  // Toolbar implement SearchFieldDelegate. But for now, we don't know how to
+  // make that happen with closure compiler.
+  function ToolbarSearchFieldDelegate(toolbar) {
+    this.toolbar_ = toolbar;
+  }
+
+  ToolbarSearchFieldDelegate.prototype = {
+    /** @override */
+    onSearchTermSearch: function(searchTerm) {
+      this.toolbar_.onSearchTermSearch(searchTerm);
+    }
+  };
+
+  return {Toolbar: Toolbar};
+});
diff --git a/chrome/browser/ui/webui/extensions/extensions_ui.cc b/chrome/browser/ui/webui/extensions/extensions_ui.cc
index bd109b0d..c3b3da21 100644
--- a/chrome/browser/ui/webui/extensions/extensions_ui.cc
+++ b/chrome/browser/ui/webui/extensions/extensions_ui.cc
@@ -32,10 +32,18 @@
       content::WebUIDataSource::Create(chrome::kChromeUIExtensionsHost);
 
   source->SetJsonPath("strings.js");
+
   source->AddLocalizedString("title",
                              IDS_MANAGE_EXTENSIONS_SETTING_WINDOWS_TITLE);
+  source->AddLocalizedString("toolbarTitle", IDS_MD_EXTENSIONS_TOOLBAR_TITLE);
+  source->AddLocalizedString("search", IDS_MD_EXTENSIONS_SEARCH);
+
+  source->AddResourcePath("manager.css", IDR_MD_EXTENSIONS_MANAGER_CSS);
   source->AddResourcePath("manager.html", IDR_MD_EXTENSIONS_MANAGER_HTML);
   source->AddResourcePath("manager.js", IDR_MD_EXTENSIONS_MANAGER_JS);
+  source->AddResourcePath("toolbar.css", IDR_MD_EXTENSIONS_TOOLBAR_CSS);
+  source->AddResourcePath("toolbar.html", IDR_MD_EXTENSIONS_TOOLBAR_HTML);
+  source->AddResourcePath("toolbar.js", IDR_MD_EXTENSIONS_TOOLBAR_JS);
   source->AddResourcePath("strings.html", IDR_MD_EXTENSIONS_STRINGS_HTML);
   source->SetDefaultResource(IDR_MD_EXTENSIONS_EXTENSIONS_HTML);
 
diff --git a/ui/webui/resources/cr_elements/v1_0/cr_search_field/cr_search_field.css b/ui/webui/resources/cr_elements/v1_0/cr_search_field/cr_search_field.css
new file mode 100644
index 0000000..cd28d1f
--- /dev/null
+++ b/ui/webui/resources/cr_elements/v1_0/cr_search_field/cr_search_field.css
@@ -0,0 +1,71 @@
+/* Copyright 2015 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+:host {
+  -webkit-padding-end: 10px;
+  box-sizing: border-box;
+  display: flex;
+  justify-content: flex-end;
+}
+
+:host paper-input-container {
+  margin-top: 2px;
+  max-width: 200px;
+  padding: 2px 0;
+  width: 100%;
+}
+
+#search-term {
+  --paper-input-container-color: rgb(192, 199, 205);
+  --paper-input-container-focus-color: rgb(192, 199, 205);
+  --paper-input-container-input: {
+    color: inherit;
+    font-family: inherit;
+    font-size: inherit;
+  };
+  --paper-input-container-input-color: rgb(192, 199, 205);
+  color: rgb(192, 199, 205);
+  z-index: 0;
+}
+
+#search-term input[type='search']::-webkit-search-decoration,
+#search-term input[type='search']::-webkit-search-cancel-button,
+#search-term input[type='search']::-webkit-search-results-button {
+  -webkit-appearance: none;
+}
+
+#search-term input[type='search']::-webkit-search-cancel-button {
+  display: block;
+  width: 20px;
+}
+
+paper-icon-button {
+  --iron-icon-height: 20px;
+  --iron-icon-width: 20px;
+  --paper-icon-button: {
+    height: 20px;
+    padding: 6px;
+    width: 20px;
+  };
+}
+
+#search-term paper-icon-button {
+  --iron-icon-height: 16px;
+  --iron-icon-width: 16px;
+  --paper-icon-button: {
+    -webkit-margin-end: -8px;
+    height: 16px;
+    padding: 8px;
+    width: 16px;
+  };
+  position: absolute;
+  right: 0;
+  top: -4px;
+  z-index: 1;
+}
+
+:host-context([dir='rtl']) #search-term paper-icon-button {
+  left: 0;
+  right: auto;
+}
diff --git a/ui/webui/resources/cr_elements/v1_0/cr_search_field/cr_search_field.html b/ui/webui/resources/cr_elements/v1_0/cr_search_field/cr_search_field.html
new file mode 100644
index 0000000..7fda23cc
--- /dev/null
+++ b/ui/webui/resources/cr_elements/v1_0/cr_search_field/cr_search_field.html
@@ -0,0 +1,28 @@
+<link rel="import" href="chrome://resources/html/assert.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/iron-icons.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-input/iron-input.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input-container.html">
+
+<dom-module id="cr-search-field">
+  <template>
+    <paper-icon-button icon="search" id="search-button"
+        disabled$="[[showingSearch_]]"
+        i18n-values="title:search"
+        on-click="toggleShowingSearch_"></paper-icon-button>
+    <template is="dom-if" if="[[showingSearch_]]" id="search-container">
+      <paper-input-container id="search-term" on-search="onSearchTermSearch_"
+          on-keydown="onSearchTermKeydown_" hidden$="[[!showingSearch_]]"
+          no-label-float>
+        <input is="iron-input" id="search-input" type="search"
+            i18n-values="placeholder:search" incremental>
+        <paper-icon-button icon="cancel" id="clear-search"
+            on-click="toggleShowingSearch_"
+            hidden$="[[!showingSearch_]]"></paper-icon-button>
+      </paper-input-container>
+    </template>
+  </template>
+  <link rel="import" type="css" href="cr_search_field.css">
+  <script src="cr_search_field.js"></script>
+</dom-module>
diff --git a/ui/webui/resources/cr_elements/v1_0/cr_search_field/cr_search_field.js b/ui/webui/resources/cr_elements/v1_0/cr_search_field/cr_search_field.js
new file mode 100644
index 0000000..a9e8ad8
--- /dev/null
+++ b/ui/webui/resources/cr_elements/v1_0/cr_search_field/cr_search_field.js
@@ -0,0 +1,65 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/** @interface */
+var SearchFieldDelegate = function() {};
+
+SearchFieldDelegate.prototype = {
+  /**
+   * @param {string} value
+   */
+  onSearchTermSearch: assertNotReached,
+};
+
+var SearchField = Polymer({
+  is: 'cr-search-field',
+
+  properties: {
+    showingSearch_: {
+      type: Boolean,
+      value: false,
+    },
+  },
+
+  /** @param {SearchFieldDelegate} delegate */
+  setDelegate: function(delegate) {
+    this.delegate_ = delegate;
+  },
+
+  /**
+   * Returns the value of the search field.
+   * @return {string}
+   */
+  getValue: function() {
+    var searchInput = this.$$('#search-input');
+    return searchInput ? searchInput.value : '';
+  },
+
+  /** @private */
+  onSearchTermSearch_: function() {
+    if (this.delegate_)
+      this.delegate_.onSearchTermSearch(this.getValue());
+  },
+
+  /** @private */
+  onSearchTermKeydown_: function(e) {
+    assert(this.showingSearch_);
+    if (e.keyIdentifier == 'U+001B')  // Escape.
+      this.toggleShowingSearch_();
+  },
+
+  /** @private */
+  toggleShowingSearch_: function() {
+    this.showingSearch_ = !this.showingSearch_;
+    this.async(function() {
+      var searchInput = this.$$('#search-input');
+      if (this.showingSearch_) {
+        searchInput.focus();
+      } else {
+        searchInput.value = '';
+        this.onSearchTermSearch_();
+      }
+    });
+  },
+});
diff --git a/ui/webui/resources/cr_elements_resources.grdp b/ui/webui/resources/cr_elements_resources.grdp
index 23df251..8b3506a 100644
--- a/ui/webui/resources/cr_elements_resources.grdp
+++ b/ui/webui/resources/cr_elements_resources.grdp
@@ -111,6 +111,15 @@
   <structure name="IDR_CR_ELEMENTS_1_0_CR_ONC_TYPES_JS"
              file="../../webui/resources/cr_elements/v1_0/network/cr_onc_types.js"
              type="chrome_html" />
+  <structure name="IDR_CR_ELEMENTS_1_0_CR_SEARCH_FIELD_CSS"
+             file="../../webui/resources/cr_elements/v1_0/cr_search_field/cr_search_field.css"
+             type="chrome_html" />
+  <structure name="IDR_CR_ELEMENTS_1_0_CR_SEARCH_FIELD_HTML"
+             file="../../webui/resources/cr_elements/v1_0/cr_search_field/cr_search_field.html"
+             type="chrome_html" />
+  <structure name="IDR_CR_ELEMENTS_1_0_CR_SEARCH_FIELD_JS"
+             file="../../webui/resources/cr_elements/v1_0/cr_search_field/cr_search_field.js"
+             type="chrome_html" />
   <structure name="IDR_CR_ELEMENTS_1_0_CR_TOGGLE_BUTTON_CSS"
              file="../../webui/resources/cr_elements/v1_0/cr_toggle_button/cr_toggle_button.css"
              type="chrome_html" />