--- title: Implement a custom component slug: '305' canonical_url: https://docs.coveo.com/en/305/ collection: javascript-search-framework source_format: adoc --- # Implement a custom component > **Note** > > When possible, create your component in [TypeScript](https://www.typescriptlang.org/). > > For more information on why it's considered a good practice, see [Create custom components](https://docs.coveo.com/en/297/). When using the Coveo JavaScript Search Framework, you will sometimes want to add your own custom components (see [Create custom components](https://docs.coveo.com/en/297/)). In this tutorial, you will be adding a rudimentary custom search box to your page using pure JavaScript. This component will execute a query every time a user selects Enter. It will also have a configurable option to enable [search-as-you-type](https://docs.coveo.com/en/2068/), meaning that a query will be sent every time the user types something when the option is enabled. ## Step 1: Create your constructor First, declare a constructor function that the framework will call to instantiate your custom search box component: ```javascript const CustomSearchbox = (function(_super) { __extends(CustomSearchbox, Coveo.Component); function CustomSearchbox(element, options, bindings) { _super.call(this, element, CustomSearchbox.ID, bindings); this.type = 'CustomSearchBox'; Coveo.Component.bindComponentToElement(element, this); this.element = element; this.options = options; this.bindings = bindings; } })(Coveo.Component); ``` The framework will automatically pass the following arguments when it calls this function: . `element`: the DOM element on which the component is being instantiated. . `options`: the options that were passed for the component in the init top-level function call. > **Important** > > The options argument contains options passed as follows: > > ```javascript Coveo.init(document.querySelector('#search'), { CustomSearchbox: { 'foo': 'bar' } }) ``` > > It does **not** contain options passed as `data-` attribute values in the component markup (for example, `div class='CustomSearchbox' data-foo='bar'>`) . `bindings`: an object that references different singletons which are used by the framework. This object has the following properties: ** `root`: the DOM element on which the main SearchInterface component is bound. ** `queryStateModel`: the State object instance, which can be used to read/write in the state of the search interface. ** `queryController`: the QueryController object instance, which can be used to execute queries in the search interface. ** `searchInterface`: the main `SearchInterface` component instance. ** `usageAnalytics`: the Analytics component instance, which can log various analytics events. ## Step 2: Add the component ID In order for your component to work, it needs an ID property that uniquely identifies the component. This property allows the Coveo JavaScript Search Framework to recognize an element with the `CoveoCustomSearchBox` class to be instantiated as a component. Add the following line after the constructor function: ```javascript CustomSearchbox.ID = 'CustomSearchbox'; ``` ## Step 3: Initialize the component In order for your component to be registered and initialized alongside the Coveo JavaScript Search Framework, call your constructor in the `registerAutoCreateComponent` function. Add the following line after the constructor function: ```javascript Coveo.Initialization.registerAutoCreateComponent(CustomSearchbox); ``` Your code should now look like this: **Example** **CustomComponent.js** ```javascript const CustomSearchbox = (function(_super) { __extends(CustomSearchbox, Coveo.Component); function CustomSearchbox(element, options, bindings) { _super.call(this, element, CustomSearchbox.ID, bindings); this.type = 'CustomSearchBox'; Coveo.Component.bindComponentToElement(element, this); this.element = element; this.options = options; this.bindings = bindings; } CustomSearchbox.ID = 'CustomSearchbox'; Coveo.Initialization.registerAutoCreateComponent(CustomSearchbox); })(Coveo.Component); ``` > **Important** > > [jsui-new Coveo JavaScript Search Framework v2.2900.23] > > > When using the Coveo JavaScript Search Framework 2.x, you can also register your component as a lazy component. > This way, your code is only initialized when you have the component on your page (see [Lazy versus eager component loading](https://docs.coveo.com/en/295#registering-a-lazy-component)). ## Step 4: Add a function to trigger a query when the Enter key is pressed As of now, your component is able to be successfully initialized, but it doesn't do anything. Since you're creating a search box, a good function to add would be to trigger a query when the Enter key is selected in the search box. . In the constructor, add an event listener on the `keyup` event. Make it so that it calls a `handleKeyUp` function. ```javascript this.element.addEventListener('keyup', (e)=> this.handleKeyUp(e)); ``` . Create the `handleKeyUp` function. It should only detect if the released key was Enter, and call the `executeNewQuery` function when it is. ```javascript CustomSearchbox.prototype.handleKeyUp = function(e) { if (e.key == 'Enter') { this.executeNewQuery(); } } ``` . Create the `executeNewQuery` function. The function should read the value entered in your component, and set it as the new query. ```javascript CustomSearchbox.prototype.executeNewQuery = function() { this.bindings.queryStateModel.set('q', this.element.value); this.bindings.queryController.executeQuery(); } ``` . In the `executeNewQuery` function, send a Usage Analytics event when the query is performed. This is so you can track what your users search (see [Why You Should Add Usage Analytics Events](#why-you-should-add-usage-analytics-events)). ```javascript CustomSearchbox.prototype.executeNewQuery = function() { this.bindings.queryStateModel.set('q', this.element.value); this.bindings.usageAnalytics.logSearchEvent({ name : 'submitSearchbox', type : 'CustomSearchbox' }); this.bindings.queryController.executeQuery(); } ``` Your code should now look like this: ```javascript const CustomSearchbox = (function(_super) { __extends(CustomSearchbox, Coveo.Component); function CustomSearchbox(element, options, bindings) { _super.call(this, element, CustomSearchbox.ID, bindings); this.type = 'CustomSearchBox'; Coveo.Component.bindComponentToElement(element, this); this.element = element; this.options = options; this.bindings = bindings; this.element.addEventListener('keyup', (e) => this.handleKeyUp(e)); } CustomSearchbox.prototype.handleKeyUp = function(e) { if (e.key == 'Enter') { this.executeNewQuery(); } } CustomSearchbox.prototype.executeNewQuery = function() { this.bindings.queryStateModel.set('q', this.element.value); this.bindings.usageAnalytics.logSearchEvent({ name: 'submitSearchbox', type: 'CustomSearchbox' }); this.bindings.queryController.executeQuery(); } CustomSearchbox.ID = 'CustomSearchbox'; Coveo.Initialization.registerAutoCreateComponent(CustomSearchbox); })(Coveo.Component); ``` > **Note** > > **Why You Should Add Usage Analytics Events**[[why-you-should-add-usage-analytics-events]] > > To get consistent data and reporting inside [Coveo Analytics](https://docs.coveo.com/en/182/), it's mandatory that every search event be logged to the service. > Otherwise, the framework will log a warning every time a query is submitted without first having logged a search event. > > If you don't log any search events when you trigger a query, in the your browser console, you will most probably see a warning like this one: > > `A search was triggered, but no analytics event was logged. > To have consistent analytics data, consider logging a search event using the methods provided by the framework` > > In a Google Chrome browser, the warning looks like this: ## Step 5: Add a search-as-you-type option You can add options to your custom component. Those options can be modified using the `data-` HTML attribute (see [ComponentOptions](https://coveo.github.io/search-ui/classes/componentoptions.html)). A nice option to have on a search box is the `search-as-you-type` function, which triggers a query while the user is typing, allowing them to preview the results while typing their query. > **Note** > > The `search-as-you-type` feature can significantly increase your query count. > If you're close to exceeding your allowed queries per month (QPM), contact your Coveo Sales representative before enabling it. . In the constructor, change the `this.options = options` line to initialize your other options (see [ComponentOptions - initComponentOptions](https://coveo.github.io/search-ui/classes/componentoptions.html#initcomponentoptions)). ```javascript this.options = Coveo.ComponentOptions.initComponentOptions(element, CustomSearchbox, options); ``` . Declare a `searchAsYouType` option on your component. You want this option to be a Boolean (see [ComponentOptions - buildBooleanOption](https://coveo.github.io/search-ui/classes/componentoptions.html#buildbooleanoption)). For this example, you can make its default value `false`. ```javascript CustomSearchbox.options = { searchAsYouType : Coveo.ComponentOptions.buildBooleanOption({defaultValue: false}) } ``` . Change your `handleKeyUp` function so that, when `searchAsYouType` is enabled, a query is performed every time a key is released instead of only when the `Enter` key is. ```javascript CustomSearchbox.prototype.handleKeyUp = function(e) { if (this.options.searchAsYouType) { this.executeNewQuery(); } else if (e.key == 'Enter') { this.executeNewQuery(); } } ``` Your code should now look like this: ```javascript const CustomSearchbox = (function(_super) { __extends(CustomSearchbox, Coveo.Component); function CustomSearchbox(element, options, bindings) { _super.call(this, element, CustomSearchbox.ID, bindings); this.type = 'CustomSearchBox'; Coveo.Component.bindComponentToElement(element, this); this.element = element; this.options = Coveo.ComponentOptions.initComponentOptions(element, CustomSearchbox, options); this.bindings = bindings; this.element.addEventListener('keyup', (e) => this.handleKeyUp(e)); } CustomSearchbox.prototype.handleKeyUp = function(e) { if (this.options.searchAsYouType) { this.executeNewQuery(); } else if (e.key == 'Enter') { this.executeNewQuery(); } } CustomSearchbox.prototype.executeNewQuery = function() { this.bindings.queryStateModel.set('q', this.element.value); this.bindings.usageAnalytics.logSearchEvent({ name : 'submitSearchbox', type : 'CustomSearchbox' }); this.bindings.queryController.executeQuery(); } CustomSearchbox.options = { searchAsYouType : Coveo.ComponentOptions.buildBooleanOption({defaultValue: false}) } CustomSearchbox.ID = 'CustomSearchbox'; Coveo.Initialization.registerAutoCreateComponent(CustomSearchbox); })(Coveo.Component); ``` You can now add `data-search-as-you-type='true'` to your `CoveoCustomSearchbox` element to enable your option. ```xml ``` ## Step 6: Add the newly created component in a search page Now that you have completed your rudimentary custom search box, you're ready to add it to your page: ```html [...]
```