{"id":23692486,"url":"https://github.com/yext/answers-search-ui","last_synced_at":"2026-02-23T22:30:02.204Z","repository":{"id":37081979,"uuid":"171958229","full_name":"yext/answers-search-ui","owner":"yext","description":"Answers Javascript API Library for building Search experiences.","archived":false,"fork":false,"pushed_at":"2024-10-17T13:54:38.000Z","size":90259,"stargazers_count":22,"open_issues_count":21,"forks_count":7,"subscribers_count":11,"default_branch":"master","last_synced_at":"2024-12-04T23:26:08.607Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yext.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-02-21T22:59:02.000Z","updated_at":"2024-10-15T19:06:34.000Z","dependencies_parsed_at":"2023-10-04T22:42:17.542Z","dependency_job_id":"54c32b96-ea97-4efd-b7e3-edc5f68899de","html_url":"https://github.com/yext/answers-search-ui","commit_stats":null,"previous_names":["yext/answers"],"tags_count":216,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yext%2Fanswers-search-ui","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yext%2Fanswers-search-ui/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yext%2Fanswers-search-ui/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yext%2Fanswers-search-ui/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yext","download_url":"https://codeload.github.com/yext/answers-search-ui/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":231810495,"owners_count":18429999,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-30T03:28:18.210Z","updated_at":"2026-02-23T22:29:57.181Z","avatar_url":"https://github.com/yext.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Answers Search UI\n\n\u003ch3\u003e\n  \u003ca href='https://coveralls.io/github/yext/answers-search-ui?branch=master'\u003e\n    \u003cimg src='https://coveralls.io/repos/github/yext/answers-search-ui/badge.svg?branch=master' alt='Coverage Status' /\u003e\n  \u003c/a\u003e\n\u003c/h3\u003e\n\n1. [Install / Setup](#install-and-setup)\n2. [ANSWERS.init Configuration Options](#answersinit-configuration-options)\n   - [Vertical Pages Configuration](#vertical-pages-configuration)\n   - [Search Configuration](#search-configuration)\n   - [Vertical No Results Configuration](#vertical-no-results-configuration)\n   - [onVerticalSearch Configuration](#onverticalsearch-configuration)\n   - [onUniversalSearch Configuration](#onuniversalsearch-configuration)\n3. [Component Usage](#component-usage)\n   - [Base Component Configuration](#base-component-configuration)\n   - [Adding a Component](#adding-a-component-to-your-page)\n   - [Removing Components](#removing-components)\n4. [Types of Built-in Components](#types-of-built-in-components)\n   - [SearchBar Component](#searchbar-component)\n   - [DirectAnswer Component](#direct-answer-component)\n   - [UniversalResults Component](#universal-results-component)\n   - [VerticalResults Component](#vertical-results-component)\n   - [VerticalResultsCount Component](#vertical-results-count-component)\n   - [Pagination Component](#pagination-component)\n   - [FilterBox Component](#filterbox-component)\n   - [Facets Component](#facets-component)\n      - [Transforming Facets](#transforming-facets)\n   - [FilterSearch Component](#filtersearch-component)\n   - [Filter Components](#filter-components)\n   - [Applied Filters Component](#applied-filters-component)\n   - [Navigation Component](#navigation-component)\n   - [QASubmission Component](#qa-submission-component)\n   - [SpellCheck Component](#spell-check-component)\n   - [LocationBias Component](#location-bias-component)\n   - [SortOptions Component](#sort-options-component)\n   - [Map Component](#map-component)\n     - [Supported Map Locales](#supported-map-locales)\n   - [Icon Component](#icon-component)\n5. [Customizing Components](#customizing-components)\n   - [Using a Custom Renderer](#using-a-custom-renderer)\n   - [Custom Data Formatting](#custom-data-formatting)\n   - [Custom Data Transforms](#custom-data-transforms)\n   - [Using a Custom Template for a Component](#using-a-custom-template-for-a-component)\n   - [Creating Custom Components](#creating-custom-components)\n6. [Extending the Built-in Renderer](#extending-the-built-in-renderer)\n   - [Custom Partials](#custom-partials)\n   - [Template Helpers](#template-helpers)\n7. [Analytics](#analytics)\n   - [Custom Analytics Using JavaScript](#custom-analytics-using-javascript)\n   - [Custom Analytics Using Data Attributes](#custom-analytics-using-data-attributes)\n   - [Built-In Analytics Events For CTAs](#built-in-analytics-events-for-ctas)\n   - [Conversion Tracking](#conversion-tracking)\n   - [On-Search Analytics](#on-search-analytics)\n8. [Rich Text Formatting](#rich-text-formatting)\n9. [Processing Translations](#processing-translations)\n10. [Performance Metrics](#performance-metrics)\n\n\n# Install and Setup\n\nThe Answers Javascript API Library does not need to be installed locally. Instead, it can be used\nwith script tags on a webpage. The instructions below explain how to do this; they will walk you through\nadding the Answers stylesheet, JS library, and an intialization script to an HTML page.\nAfter doing this, you can view your page in the browser.\n\nInclude the Answers CSS\n```html\n\u003clink rel=\"stylesheet\" type=\"text/css\" href=\"https://assets.sitescdn.net/answers/answers.css\"\u003e\n```\n\nAdd the Javascript library and placeholder elements for [Answers components](#component-usage).\n```html\n\u003cscript src=\"https://assets.sitescdn.net/answers/answers.min.js\" onload=\"ANSWERS.domReady(initAnswers)\" defer async\u003e\u003c/script\u003e\n\n\u003cdiv id=\"SearchBarContainer\"\u003e\u003c/div\u003e\n\u003cdiv id=\"UniversalResultsContainer\"\u003e\u003c/div\u003e\n```\n\nAdd an initialization script with an apiKey or token, experienceKey and onReady function. In the example below, we've initialized two\nbasic components with apiKey: [SearchBar](#searchbar-component) and [UniversalResults](#universal-results-component).\n```js\nfunction initAnswers() {\n  ANSWERS.init({\n    apiKey: '\u003cAPI_KEY_HERE\u003e', // See [1]\n    experienceKey: '\u003cEXPERIENCE_KEY_HERE\u003e',\n    onReady: function() {\n      ANSWERS.addComponent('SearchBar', {\n        container: '#SearchBarContainer',\n      });\n\n      ANSWERS.addComponent('UniversalResults', {\n        container: '#UniversalResultsContainer',\n      });\n    }\n  })\n}\n```\n\nANSWERS.init() returns a promise which optionally allows components to be added using promise syntax\n```js\nfunction initAnswers() {\n  ANSWERS.init({\n    apiKey: '\u003cAPI_KEY_HERE\u003e', // See [1]\n    experienceKey: '\u003cEXPERIENCE_KEY_HERE\u003e',\n  }).then(function() {\n    ANSWERS.addComponent('SearchBar', {\n      container: '#SearchBarContainer',\n    });\n\n    ANSWERS.addComponent('UniversalResults', {\n      container: '#UniversalResultsContainer',\n    });\n  });\n}\n```\n\n[1] Learn more about [getting your API key](https://developer.yext.com/docs/guides/get-started/).\n\n# ANSWERS.init Configuration Options\n\nThe configuration provided here is configuration that is shared across components.\n\n```js\nfunction initAnswers() {\n  ANSWERS.init({\n    // Required*, your Yext Answers API key. *Do NOT provide apiKey if token is used.\n    apiKey: '\u003cAPI_KEY_HERE\u003e',\n    // Required*, custom auth token. *Do NOT provide token if apiKey is used.\n    token: '\u003cTOKEN_HERE\u003e',\n    // Required, the key used for your Answers experience\n    experienceKey: '\u003cEXPERIENCE_KEY_HERE\u003e',\n    // Optional, indicates the environment to run Answers experience in ('production' or 'sandbox')\n    environment: '\u003cENVIRONMENT_HERE',\n    // Optional, visitor interacting with the experience, see Visitor Configuration below for details\n    visitor: {\n      // Required, see below\n      id: '\u003cID_HERE\u003e',\n      // Optional, see below\n      idMethod: '\u003cID_METHOD_HERE\u003e',\n    },\n    // Optional, initialize components here, invoked when the Answers component library is loaded/ready.\n    //    If components are not added here, they can also be added when the init promise resolves\n    onReady: function() {},\n    // Optional*, Yext businessId, *required to send analytics events\n    businessId: 'businessId',\n    // Optional, if false, the library will not fetch pre-made templates. Only use change this to false if you provide a\n    //    template bundle in the `templateBundle` config option or implement custom renders for every component\n    useTemplates: true,\n    // Optional, additional templates to register with the renderer\n    templateBundle: {},\n    // Optional, provide configuration for each vertical that is shared across components, see Vertical Pages Configuration below\n    verticalPages: [],\n    // Optional, search specific settings, see Search Configuration below\n    search: {},\n    // Optional, vertical no results settings, see Vertical No Results below\n    noResults: {},\n    // Optional, the locale will affect how queries are interpreted and the results returned. Defaults to 'en'.\n    locale: 'en',\n    // Optional, the Answers Experience version to use for api requests\n    experienceVersion: 'PRODUCTION',\n    // Optional, prints full Answers error details when set to `true`. Defaults to false.\n    debug: false,\n    // Optional, If true, the search session is tracked. If false, there is no tracking. Defaults to true.\n    sessionTrackingEnabled: true,\n    // Optional, invoked when the state of any component changes\n    onStateChange: function() {},\n    // Optional, analytics callback after a vertical search, see onVerticalSearch Configuration for additional details\n    onVerticalSearch: function() {},\n    // Optional, analytics callback after a universal search, see onUniversalSearch Configuration for additional details\n    onUniversalSearch: function() {},\n    // Optional, opt-out of automatic css variable resolution on init for legacy browsers\n    disableCssVariablesPonyfill: false,\n    // Optional, the analytics key describing the Answers integration type. Accepts 'STANDARD', 'OVERLAY', or arbitrary strings. Defaults to 'STANDARD'\n    querySource: 'STANDARD',\n    // Optional, additional values for the HTTP headers listed below. Headers other than those listed below will be ignored.\n    additionalHttpHeaders: {\n      // Additional key-value pairs to send in the Client-SDK header.\n      // ANSWERS_CORE and ANSWERS_SEARCH_UI_SDK are automatically set and cannot be overwritten.\n      'Client-SDK': {}\n    }\n  })\n}\n```\n\n## Vertical Pages Configuration\nBelow is a list of configuration options related to vertical pages in navigation and no results, used in the [base configuration](#answersinit-configuration-options) above.\n\n```js\nverticalPages: [\n  {\n    // Required, the label for this page\n    label: 'Home',\n    // Required, the link to this page\n    url: './index.html',\n    // Optional*, the verticalKey, *required for vertical pages (must omit this property for universal)\n    verticalKey: 'locations',\n    // Optional, the icon name to use in no results, defaults to no icon\n    icon: 'star',\n    // Optional, the URL icon to use in no results, defaults to no icon\n    iconUrl: '',\n    // Optional, if true, will show this page first in the Navigation Component, defaults to false\n    isFirst: false,\n    // Optional, if true, will add a special styling to this page in the Navigation Component, defaults to false\n    isActive: false,\n    // Optional, if true, hide this tab in the Navigation Component, defaults to false\n    hideInNavigation: false,\n  },\n  ...\n]\n```\n\n## Search Configuration\nBelow is a list of configuration options related to search, used in the [base configuration](#answersinit-configuration-options) above.\n\n```js\n    search: {\n      // Optional, the vertical key to use for searches\n      verticalKey: 'verticalKey',\n      // Optional, the number of results to display per page, defaults to 20. Maximum is 50.\n      limit: '20',\n      // Optional, an object containing the number of results to display per vertical key. Minimum is 1. Maximum is 50.\n      // The default value is determined by the API at 10.\n      universalLimit: {\n        verticalKey1: 20,\n        verticalKey2: 49\n      },\n      // Optional, Vertical Pages only, a default search to use on page load when the user hasn't provided a query\n      defaultInitialSearch: 'What is Yext Answers?',\n    },\n```\n\n## Vertical No Results Configuration\nBelow is a list of configuration options related to no results on Vertical Pages, used in the [base configuration](#answersinit-configuration-options) above.\n\n```js\n    noResults: {\n      // Optional, whether to display all results for the Vertical when a query has no results, defaults to false\n      displayAllResults: false,\n      // Optional, a custom template for the no results card\n      template: '',\n    },\n```\n\n## onVerticalSearch Configuration\n\nThe onVerticalSearch Configuration is a function, used in the [base configuration](#answersinit-configuration-options) above.\n\nIt allows you to send an analytics event each time a search is run on a Vertical page. This function should take in one parameter, `searchParams`, which contains information about the search, and return the desired analytics event.\n\nLike all Answers Javascript API Library analytics, this will only work if there is a businessId in the ANSWERS.init.\n\nThe search information exposed in `searchParams` is shown below.\n\n```js\nfunction (searchParams) =\u003e {\n    /**\n     * Vertical key used for the search.\n     * @type {string}\n     */\n    const verticalKey = searchParams.verticalKey;\n\n    /**\n     * The string being searched for.\n     * @type {string}\n     */\n    const queryString = searchParams.queryString;\n\n    /**\n     * The total number of results found.\n     * @type {number}\n     */\n    const resultsCount = searchParams.resultsCount;\n\n    /**\n     * Either 'normal' or 'no-results'.\n     * @type {string}\n     */\n    const resultsContext = searchParams.resultsContext;\n\n    let analyticsEvent = new ANSWERS.AnalyticsEvent('ANALYTICS_EVENT_TYPE');\n    analyticsEvent.addOptions({\n      label: 'Sample analytics event',\n      searcher: 'VERTICAL',\n      query: queryString,\n      resultsCount: resultsCount,\n      resultsContext: resultsContext,\n    });\n    return analyticsEvent;\n  },\n}),\n```\n\n## onUniversalSearch Configuration\n\nThe onUniversalSearch Configuration is a function, used in the [base configuration](#answersinit-configuration-options) above.\n\nIt allows you to send an analytics event each time a search is run\non a Universal page. This function should take in one parameter, `searchParams`, which contains information about the\nsearch, and return the desired analytics event.\n\nLike all Answers Javascript API Library analytics, this will only work if there is a businessId in the ANSWERS.init.\n\nThe search information exposed in `searchParams` is shown below.\n```js\nfunction (searchParams) =\u003e {\n    /**\n     * The string being searched for.\n     * @type {string}\n     */\n    const queryString = searchParams.queryString;\n\n    /**\n     * The total number of results found.\n     * @type {number}\n     */\n    const sectionsCount = searchParams.sectionsCount;\n\n    /**\n     * A map containing entries of the form:\n     * { totalResultsCount: 150, displayedResultsCount: 10}\n     * for each returned vertical. The totalResultsCount indicates how many results\n     * are present in the vertical. The displayResultsCount indicates how many of\n     * those results are actually displayed.\n     * @type {Object\u003cstring,Object\u003e}\n     */\n    const resultsCountByVertical = searchParams.resultsCountByVertical;\n\n    let analyticsEvent = new ANSWERS.AnalyticsEvent('ANALYTICS_EVENT_TYPE');\n    analyticsEvent.addOptions({\n      type: 'ANALYTICS_EVENT_TYPE',\n      label: 'Sample analytics event',\n      searcher: 'UNIVERSAL',\n      query: queryString\n      sectionsCount: sectionsCount,\n    });\n    return analyticsEvent;\n  },\n}),\n```\n\n## Visitor Configuration\n\nBelow is a list of configuration attributes related to a visitor, used in the [base configuration](#answersinit-configuration-options) above.\n\nThe visitor object ties a user's identity to their searches and actions. The visitor can also be set or changed using the `ANSWERS.setVisitor` function.\n\n```js\n    visitor: {\n      // Required, the ID associated with the user. This will be the yextUserId if Yext Auth is used. Max of 64 characters.\n      id: '123919',\n      // Optional, the method used to generate the visitor ID. Max of 16 characters.\n      idMethod: 'YEXT_USER',\n    },\n```\n\n# Component Usage\n\nThe Answers Component Library exposes an easy to use interface for adding and customizing various types of UI components on your page.\n\n## What is a Component?\n\nAt a high level, components are the individual pieces of an Answers page. The Answers Javascript API Library comes with many types of components. Each component is an independent, reusable piece of code. A component fills an HTML element container that the implementer provides on the page. Components are updated from their config, the config from the ANSWERS.init, and potentially an API response.\n\nEach type of Component has its own custom configurations. Additionally, all components share the base configuration options defined above. We will provide a brief description below of what each component does, along with describing how it can be configured.\n\n\n## Base Component Configuration\n\nEvery component has the same base configuration options.\n```js\n  {\n    // Required, the selector for the container element where the component will be injected\n    container: 'container',\n    // Optional, a unique name for the component\n    name: 'name',\n    // Optional, an additional, custom HTML classname for the component. The component will also \n    // have a classname of 'yxt-Answers-component' applied.\n    class: 'class',\n    // Optional, handlebars template or HTML to override built-in handlebars template for the component\n    template: 'template',\n    // Optional, override render function\n    render: function(data) {},\n    // Optional, a hook for transforming data before it gets sent to render\n    transformData: function(data) {},\n    // Optional, invoked when the HTML is mounted to the DOM, this will not override any built-in onMount function for a component\n    onMount: function(data) {},\n    // Optional, invoked when the HTML is mounted to the DOM, this will override any built-in onMount function for a component\n    onMountOverride: function(data) {},\n    // Optional, additional properties to send with every analytics event\n    analyticsOptions: {},\n  }\n```\n\n\n## Adding a Component to Your Page\nAdding a component to your page is super easy!\nYou can add many different [types](#types-of-built-in-components) of components to your page.\nEach component supports the base configuration options above, as well as their own unique configurations.\n\nTo start, every component requires an HTML container.\n\n```html\n\u003cdiv class=\"search-container\"\u003e\u003c/div\u003e\n```\n\nThen, you can add a component to your page through the ANSWERS add interface. You need to call `addComponent` from `onReady`.\n\nThis is an example of the `SearchBar`. See [Types of Built-in Components](#types-of-built-in-components) below.\n\n```js\nANSWERS.addComponent('SearchBar', {\n  container: '.search-container'\n})\n```\n\n## Removing Components\nIf you'd like to remove a component and all of its children, you can do it. Simply `ANSWERS.removeComponent(\u003ccomponent name\u003e)`:\n\n```js\nANSWERS.addComponent('SearchBar', {\n  container: '.search-container',\n  name: 'MySearchBar'\n})\n\nANSWERS.removeComponent('MySearchBar');\n```\n\n# Types of Built-in Components\n\n## SearchBar Component\n\nThe SearchBar component is the main entry point for search querying. It provides the input box, where the user\ntypes their query, as well as the autocomplete behavior.\n\n```html\n\u003cdiv class=\"search-query-container\"\u003e\u003c/div\u003e\n```\n\nIf the `verticalKey` config option is omitted, the SearchBar will perform Universal searches. Universal\nsearches return results across multiple Verticals; Vertical searches search within one Vertical. Additionally, Universal search and Vertical search provide a different way of auto complete.\n\n```js\nANSWERS.addComponent('SearchBar', {\n  // Required, the selector for the container element where the component will be injected\n  container: '.search-query-container',\n  // Required* for Vertical pages, omit for Universal pages\n  verticalKey: '\u003cVERTICAL_KEY\u003e',\n  // Optional, title is not present by default\n  title: 'Search my Brand',\n  // Optional, the initial query string to use for the input box\n  query: 'query',\n  // Optional, defaults to 'Conduct a search'\n  labelText: 'What are you looking for?',\n  // Optional, used for labeling the submit button, also provided to the template\n  submitText: 'Submit',\n  // Optional, used for labeling the clear button, also provided to the template\n  clearText: 'Clear',\n  // Optional, used to specify a different built-in icon for the submit button. Defaults to Animated Magnifying glass when CSS is included.\n  submitIcon: 'iconName',\n  // Optional, a url for a custom icon for the submit button. Defaults to Animated Magnifying glass when CSS is included.\n  customIconUrl: 'path/to/icon',\n  // Optional, the query text to show as the first item for auto complete\n  promptHeader: 'Header',\n  // Optional, no default\n  placeholderText: 'Start typing...',\n  // Optional, auto focuses the search bar. Defaults to false\n  autoFocus: false,\n  // Optional, opens the autocomplete suggestions on page load. Defaults to false. Requires autoFocus to be set to true\n  autocompleteOnLoad: false,\n  // Optional, allows a user to conduct an empty search. Should be set to true if the defaultInitialSearch is \"\".\n  allowEmptySearch: false,\n  // Optional, defaults to 300ms (0.3 seconds)\n  searchCooldown: 2000,\n  // Optional, asks the user for their geolocation when \"near me\" intent is detected\n  promptForLocation: true,\n  // Optional, displays an \"x\" button to clear the current query when true\n  clearButton: true,\n  // Optional, redirect search query to url\n  redirectUrl: 'path/to/url',\n  // Optional, target frame for the redirect url, defaults to current frame. Expects a valid target: \"_blank\", \"_self\", \"_parent\", \"_top\" or the name of a frame\n  redirectUrlTarget: '_self',\n  // Optional, defaults to native form node within container\n  formSelector: 'form',\n  // Optional, defaults to true. When true, a form is used as the query submission context.\n  // Note that WCAG compliance is not guaranteed if a form is not used as the context.\n  useForm: 'true',\n  // Optional, the input element used for searching and wires up the keyboard interaction\n  inputEl: '.js-yext-query',\n  // Optional, options to pass to the geolocation api, which is used to fetch the user's current location.\n  // https://developer.mozilla.org/en-US/docs/Web/API/PositionOptions\n  geolocationOptions: {\n    // Optional, whether to improve accuracy at the cost of response time and/or power consumption, defaults to false.\n    enableHighAccuracy: false,\n    // Optional, the maximum amount of time (in ms) a geolocation call is allowed to take before defaulting, defaults to 1 second.\n    timeout: 1000,\n    // Optional, the maximum amount of time (in ms) to cache a geolocation call, defaults to 5 minutes.\n    maximumAge: 300000,\n  },\n  // Optional, options for an alert when the geolocation call fails.\n  geolocationTimeoutAlert: {\n    // Optional, whether to display a window.alert() on the page, defaults to false.\n    enabled: false,\n    // Optional, the message in the alert. Defaults to the below\n    message: \"We are unable to determine your location\"\n  },\n  // Optional, functions invoked when certain events occur\n  customHooks: {\n    // Optional, a callback invoked when the clear search button is clicked\n    onClearSearch: function() {},\n    // Optional, a function invoked when a search is conducted. The search terms are passed in as a string\n    onConductSearch: function(searchTerms) {}\n  },\n  // Optional, options to pass to the autocomplete component\n  autocomplete: {\n    // Optional, boolean used to hide the autocomplete when the search input is empty (even if the\n    // input is focused). Defaults to false.\n    shouldHideOnEmptySearch: false,\n    // Optional, callback invoked when the autocomplete component changes from open to closed.\n    onClose: function() {},\n    // Optional, callback invoked when the autocomplete component changes from closed to open.\n    onOpen: function() {},\n    // Optional, a string array of custom prompts to include in the autocomplete dropdown.\n    customPrompts: []\n  },\n  // Optional, options for loading indicator on seachbar\n  loadingIndicator: {\n    // Optional, whether to include a loading indicator on seachbar\n    display: false,\n    // Optional, use custom icon url instead of the default loading indicator animation\n    iconUrl: \"\"\n  },\n  // Optional, options for voice search feature on seachbar\n  voiceSearch: {\n    // Optional, whether or not voice search is enabled\n    enabled: false,\n    // Optional, provide custom mic icon url to override the voice start icon\n    customMicIconUrl: \"\",\n    // Optional, provide custom listening icon url to override the voice stop icon\n    customListeningIconUrl: \"\"\n  }\n})\n```\n\n## Direct Answer Component\n\nThis component is for Universal pages only.\n\nThe Direct Answer Component will render the BEST result, if found, based on the query.\n\n```html\n\u003cdiv class=\"direct-answer-container\"\u003e\u003c/div\u003e\n```\n\n```js\nANSWERS.addComponent('DirectAnswer', {\n  // Required, the selector for the container element where the component will be injected\n  container: '.direct-answer-container',\n  // Optional, a custom direct answer card to use, which is the default when there are no matching card overrides.\n  // See the Custom Direct Answer Card section below.\n  defaultCard: 'MyCustomDirectAnswerCard',\n  // Optional, the selector for the form used for submitting the feedback\n  formEl: '.js-directAnswer-feedback-form',\n  // Optional, the selector to bind ui interaction to for reporting\n  thumbsUpSelector: '.js-directAnswer-thumbUp',\n  // Optional, the selector to bind ui interaction to for reporting\n  thumbsDownSelector: '.js-directAnswer-thumbDown',\n  // Optional, the display text for the View Details click to action link\n  viewDetailsText: 'View Details',\n  // Optional, the screen reader text for positive feedback on the answer\n   positiveFeedbackSrText: 'This answered my question',\n  // Optional, the screen reader text for negative feedback on the answer\n   negativeFeedbackSrText: 'This did not answer my question',\n  // Optional, the footer text to display on submission of feedback\n  footerTextOnSubmission: 'Thank you for your feedback!',\n  // Optional, specify card types and overrides based on the direct answer type. The first matching cardOverride will be used, otherwise the cardType is used\n  types: {\n    'FEATURED_SNIPPET': {\n      cardType: \"documentsearch-standard\",\n      cardOverrides: [\n        {\n          fieldName: 'description',\n          entityType: 'ce_menuItem',\n          cardType: 'MenuItemDescriptionDirectAnswer'\n        },\n        {\n          fieldName: 'description',\n          entityType: 'ce_menuItem',\n          fieldType: 'rich_text'\n          cardType: 'MenuItemDescriptionDirectAnswer'\n        }\n      ]\n    },\n    'FIELD_VALUE': {\n      cardType: \"allfields-standard\",\n      cardOverrides: [\n        {\n          cardType: 'MenuItemDescriptionDirectAnswer',\n          fieldName: 'description',\n          entityType: 'ce_menuItem',\n          fieldType: 'rich_text'\n        }\n      ]\n    }\n  }\n  // DEPRECATED: use the types option instead\n  // Optional, card overrides that allow you to specify a specific direct answers card depending on the fieldName, entityType, and fieldType of the direct answer. The first matching card will be used, otherwise defaultCard will be used.\n  cardOverrides: [\n    {\n      cardType: 'MenuItemDescriptionDirectAnswer',\n      fieldName: 'description',\n      entityType: 'ce_menuItem',\n      fieldType: 'rich_text'\n    },\n    {\n      cardType: 'DeliveryHoursDirectAnswer',\n      fieldName: 'c_deliveryHours'\n    },\n    {\n      cardType: 'PhoneDirectAnswer',\n      fieldType: 'phone'\n    }\n  ]\n})\n```\n\n## Creating a Custom Direct Answer Card\n\nYou can customize the look and behavior of your Direct Answer by creating a custom Direct Answer card.\n\nA custom Direct Answer card is given the same data as the built-in card.\nThat data will look something like the below:\n\n```js\n{\n  type: \"FIELD_VALUE\",\n  answer: {\n    entityName: \"Entity Name\",\n    fieldName: \"Phone Number\",\n    fieldApiName: \"mainPhone\",\n    value: \"+11234567890\",\n    fieldType: \"phone\" \n  },\n  relatedItem: { \n    verticalConfigId: 'people',\n    data: { \n      id: \"Employee-2116\",\n      type: \"ce_person\",\n      fieldValues: {\n        description: \"This is the description field.\",\n        name: \"First Last\",\n        firstName: \"First\",\n        lastName: \"Last\",\n        mainPhone: \"+1234567890\",\n      }\n    }\n  }\n}\n```\n\nA custom Direct Answer card needs a corresponding template.\nThis can be added either inline by changing the component's constructor to:\n\n```js\n    constructor(config, systemConfig) {\n      super(config, systemConfig);\n      this.setTemplate(`\u003cdiv\u003e your template here \u003c/div\u003e`)\n    }\n```\n\nOr by including a custom template bundle, and adding:\n\n```js\n  static defaultTemplateName () {\n    return 'CustomDirectAnswerTemplate';\n  }\n```\n\nWhere 'CustomDirectAnswerTemplate' is the name the template is registered under.\n\nWe will use the following template for our example card.\n\n```hbs\n  \u003cdiv class=\"customDirectAnswer\"\u003e\n    \u003cdiv class=\"customDirectAnswer-type\"\u003e\n      {{type}}\n    \u003c/div\u003e\n    \u003cdiv class=\"customDirectAnswer-value\"\u003e\n      {{#each customValue}}\n      {{#if url}}\n        {{\u003e valueLink }}\n      {{else}}\n        {{{this}}}\n      {{/if}}\n      {{/each}}\n    \u003c/div\u003e\n    {{\u003e feedback}}\n  \u003c/div\u003e\n\n  {{#*inline 'feedback'}}\n  \u003cspan class=\"customDirectAnswer-thumbsUpIcon js-customDirectAnswer-thumbsUpIcon\"\n    data-component=\"IconComponent\"\n    data-opts='{\"iconName\": \"thumb\"}'\n  \u003e\u003c/span\u003e\n  \u003cspan class=\"customDirectAnswer-thumbsDownIcon js-customDirectAnswer-thumbsDownIcon\"\n    data-component=\"IconComponent\"\n    data-opts='{\"iconName\": \"thumb\"}'\n  \u003e\u003c/span\u003e\n  {{/inline}}\n\n  {{#*inline 'valueLink'}}\n  \u003ca class=\"customDirectAnswer-fieldValueLink\" href=\"{{{url}}}\"\n    {{#if @root/eventType}}data-eventtype=\"{{@root/eventType}}\"{{/if}}\n    {{#if @root/eventOptions}}data-eventoptions='{{{ json @root/eventOptions }}}'{{/if}}\u003e\n    {{{displayText}}}\n  \u003c/a\u003e\n  {{/inline}}\n```\n\nThis specific example needs some css to flip the thumbs up icon the right way.\n\n```css\n  .customDirectAnswer-thumbsUpIcon svg {\n    transform: rotate(180deg);\n  }\n```\n\nThis is the javascript class for our custom Direct Answer card.\nIt applies custom formatting to the Direct Answer, registers analytics events\nto the thumbs up/down icons, and passes custom event options into the template.\n\n```js\n  class CustomDirectAnswerClass extends ANSWERS.Component {\n    constructor(config, systemConfig) {\n      // If you need to override the constructor, make sure to call super(config, systemConfig) first.\n      super(config, systemConfig);\n\n      // For simplicity's sake, we set this card's template using setTemplate(), as opposed to\n      // a custom template bundle.\n      this.setTemplate(`\u003cdiv\u003e your template here \u003c/div\u003e`)\n    }\n\n    /**\n     * setState() lets you pass variables directly into your template.\n     * Here, data is the directAnswer data from the query.\n     * Below, we pass through a custom direct answers value, customValue.\n     * @param {Object} data\n     * @returns {Object}\n     */ \n    setState(data) {\n      const { type, answer, relatedItem } = data;\n      const associatedEntityId = data.relatedItem \u0026\u0026 data.relatedItem.data \u0026\u0026 data.relatedItem.data.id;\n      const verticalConfigId = data.relatedItem \u0026\u0026 data.relatedItem.verticalConfigId;\n      return super.setState({\n        ...data,\n        customValue: this.getCustomValue(answer),\n        eventType: 'CUSTOM_EVENT',\n        eventOptions: {\n          searcher: 'UNIVERSAL',\n          verticalConfigId: verticalConfigId,\n          entityId: associatedEntityId,\n        }\n      });\n    }\n\n    /**\n     * onMount() lets you register event listeners. Here, we register the thumbs up and thumbs\n     * down buttons to fire an analytics event on click.\n     */ \n    onMount() {\n      const thumbsUpIcon = this._container.querySelector('.js-customDirectAnswer-thumbsUpIcon');\n      const thumbsDownIcon = this._container.querySelector('.js-customDirectAnswer-thumbsDownIcon');\n      thumbsUpIcon.addEventListener('click', () =\u003e this.reportQuality(true));\n      thumbsDownIcon.addEventListener('click', () =\u003e this.reportQuality(false));\n    }\n\n    /**\n     * reportQuality() sends an analytics event (either THUMBS_UP or THUMBS_DOWN).\n     * @param {boolean} isGood true if the answer is what you were looking for\n     */\n    reportQuality(isGood) {\n      const eventType = isGood === true ? 'THUMBS_UP' : 'THUMBS_DOWN';\n      const event = new ANSWERS.AnalyticsEvent(eventType).addOptions({\n        directAnswer: true\n      });\n      this.analyticsReporter.report(event);\n    }\n\n    /**\n     * Formats a Direct Answer value based on its fieldType.\n     * @param {Object} answer the answer property in the directAnswer model\n     * @returns {string}\n     */ \n    formatValue(answer) {\n      const { fieldType, value } = answer;\n      switch (fieldType) {\n        case 'phone':\n          return {\n              url: 'http://myCustomWebsite.com/?mainPhone=' + value,\n              displayText: value,\n            };\n        case 'rich_text':\n          return ANSWERS.formatRichText(value);\n        case 'single_line_text':\n        case 'multi_line_text':\n        default:\n          return value;\n      }\n    }\n\n    /**\n     * Computes a custom Direct Answer. If answer.value is an array, this method\n     * formats every value in the array and returns it, otherwise it just formats the single\n     * given value.\n     * @param {Object} answer\n     * @returns {Array\u003cstring\u003e}\n     */ \n    getCustomValue(answer) {\n      if (Array.isArray(answer.value)) {\n        return answer.value.map(value =\u003e this.formatValue(answer))\n      } else {\n        return [ this.formatValue(answer) ];\n      }\n    }\n\n    /**\n     * The name of your custom direct answer card. THIS is the value you will use in any config,\n     * such as defaultCard, when you want to specify this custom Direct Answer card.\n     * @returns {string}\n     */\n    static get type() {\n      return 'MyCustomDirectAnswerCard';\n    }\n  }\n\n  // Don't forget to register your Direct Answer card within the SDK. Otherwise the SDK won't recognize your card name!\n  ANSWERS.registerComponentType(CustomDirectAnswerClass);\n```\n\n## Universal Results Component\n\nThe Universal Results component will render the results of a query,\nacross all configured verticals, with one section per vertical.\n\n```html\n\u003cdiv class=\"universal-results-container\"\u003e\u003c/div\u003e\n```\n\n```js\nANSWERS.addComponent('UniversalResults', {\n  // Required, the selector for the container element where the component will be injected\n  container: '.universal-results-container',\n  // Settings for the applied filters bar in the results header. These settings can be overriden in the\n  // \"config\" option below on a per-vertical basis.\n  appliedFilters: {\n    // If true, show any applied filters that were applied to the universal search. Defaults to true\n    show: true,\n    // If appliedFilters.show is true, whether to display the field name of an applied filter, e.g. \"Location: Virginia\" vs just \"Virginia\". Defaults to false.\n    showFieldNames: false,\n    // If appliedFilters.show is true, this is list of filters that should not be displayed.\n    // By default, builtin.entityType will be hidden\n    hiddenFields: ['builtin.entityType'],\n    // The character that separates the count of results (e.g. “1-6”) from the applied filter bar. Defaults to '|'\n    resultsCountSeparator: '|',\n    // Whether to display the change filters link in universal results. Defaults to false.\n    showChangeFilters: false,\n    // The text for the change filters link. Defaults to 'change filters'.\n    changeFiltersText: 'change filters',\n    // The character that separates each field (and its associated filters) within the applied filter bar. Defaults to '|'\n    delimiter: '|',\n    // The aria-label given to the applied filters bar. Defaults to 'Filters applied to this search:'.\n    labelText: 'Filters applied to this search:',\n  },\n  // Optional, configuration for each vertical's results\n  config: {\n    people: { // The verticalKey\n      card: {\n        // Configuration for the cards in this vertical, see Cards\n      },\n      // Optional: A custom handlebars template for this section\n      template: '\u003cdiv\u003e Custom section template \u003c/div\u003e',\n      // The title of the vertical\n      // Defaults to the vertical key, in this example 'people'\n      title: 'People',\n      // Icon to display to the left of the title. Must be one of our built-in icons, defaults to 'star'\n      icon: 'star',\n      // The url for both the viewMore link and the change-filters link. Defaults to '{{VERTICAL_KEY}}.html',\n      // in this case that is 'people.html'\n      url: 'people.html',\n      // Whether to display a view more link. Defaults to true\n      viewMore: true,\n      // The text for the view more link, if viewMore is true. Defaults to 'View More'\n      viewMoreLabel: 'View More!',\n      // Config for the applied filters bar in the results header.\n      appliedFilters: {\n        // Same as appliedFilters settings above. Settings specified here will override any top level settings.\n      },\n      // If true, display the count of results at the very top of the results. Defaults to false.\n      showResultCount: true,\n      // If true, display the total number of results. Defaults to true\n      // Optional, whether to use the AccordionResults component instead of VerticalResults for this vertical\n      useAccordion: false,\n      // Optional, whether to include a map with this vertical's results, defaults to false\n      includeMap: true,\n      // Optional*, if includeMap is true, this is required\n      mapConfig: {\n        // Required, either 'mapbox' or 'google', not case sensitive\n        mapProvider: 'google',\n        // Required, API key for the map provider\n        apiKey: '\u003c\u003c\u003c enter your api key here \u003e\u003e\u003e',\n        // ... Optional, any other config for the Map Component, find more info in the section \"Map Component\"\n      },\n      // Optional, override the render function for each result in this vertical\n      renderItem: function(data) {},\n      // Optional, override the handlebars template for each item in this vertical\n      itemTemplate: `my item {{name}}`,\n      // DEPRECATED, please use viewMoreLabel instead. viewAllText is a synonym for viewMoreLabel, where viewMoreLabel takes precedence over viewAllText. Defaults to 'View More'.\n      viewAllText: 'View All Results For Vertical'\n    }\n  },\n  // Optional, override the render function for each item in the result list\n  renderItem: function(data) {},\n  // Optional, override the handlebars template for each item in the result list\n  itemTemplate: `my item {{name}}`,\n})\n```\n\n## Vertical Results Component\n\nThe Vertical Results component shares all the same configurations from Universal Results, but you don't need to specifiy a config or context. You may limit the number of search results returned, with a maximum of 50.\n\nYou define all the options at the top level object.\n\n```html\n\u003cdiv class=\"vertical-results-container\"\u003e\u003c/div\u003e\n```\n\n```js\nANSWERS.addComponent('VerticalResults', {\n  // Required, the selector for the container element where the component will be injected\n  container: '.vertical-results-container',\n  // Optional, function to give each result item custom rendering\n  renderItem: () =\u003e {},\n  // Optional, string to give custom template to result item\n  itemTemplate: `\u003cdiv\u003e Custom template \u003c/div\u003e`,\n  // Optional, set a max number of columns to display at the widest breakpoint. Possible values are 1, 2, 3 or 4, defaults to 1\n  maxNumberOfColumns: 1,\n  // Optional, a modifier that will be appended to a class on the results list like this `yxt-Results--{modifier}`\n  modifier: '',\n  // Optional, whether to hide the default results header that VerticalResults provides. Defaults to false.\n  hideResultsHeader: false,\n  // Optional, the card used to display each individual result, see the Cards section for more details,\n  card: {\n    // Optional, The type of card, built-in types are: 'Standard', 'Accordion', and 'Legacy'. Defaults to 'Standard'\n    cardType: 'Standard',\n    // Optional, see Data Mappings for more details\n    dataMappings: () =\u003e {},\n    // Optional, see Calls To Action for more details\n    callsToAction: () =\u003e []\n  },\n  // Optional, configuration for what to display when no results are found.\n  noResults: {\n    // Optional, used to specify a custom template for the no results card, defaults to a built-in template.\n    template: '\u003cdiv\u003e \u003cem\u003eNo results found!\u003c/em\u003e Try again? \u003c/div\u003e',\n    // Optional, whether to display all results in the vertical when no results are found. Defaults to false, in which case only the no results card will be shown.\n    displayAllResults: false\n  },\n\n  /**\n   * NOTE: The config options below are DEPRECATED.\n   * They will still work as expected, and the defaults will still be applied,\n   * but future major versions of the SDK will remove them.\n   * We recommend setting hideResultsHeader to true, and using the VerticalResultsCount and AppliedFilters components instead.\n   */\n  // Optional, whether to display the total number of results, default true\n  showResultCount: true,\n  // Optional, a custom template for the results count. You can specify the variables resultsCountStart, resultsCountEnd, and resultsCount.\n  resultsCountTemplate: '\u003cdiv\u003e{{resultsCountStart}} - {{resultsCountEnd}} of {{resultsCount}}\u003c/div\u003e',\n  // Configuration for the applied filters bar in the header.\n  appliedFilters: {\n    // If true, show any applied filters that were applied to the vertical search. Defaults to true\n    show: true,\n    // If appliedFilters.show is true, whether to display the field name of an applied filter, e.g. \"Location: Virginia\" vs just \"Virginia\". Defaults to false.\n    showFieldNames: false,\n    // If appliedFilters.show is true, this is list of filters that should not be displayed.\n    // By default, builtin.entityType will be hidden\n    hiddenFields: ['builtin.entityType'],\n    // The character that separates the count of results (e.g. “1-6”) from the applied filter bar. Defaults to '|'\n    resultsCountSeparator: '|',\n    // If the filters are shown, whether or not they should be removable buttons. Defaults to false.\n    removable: false,\n    // The character that separates each field (and its associated filters) within the applied filter bar. Defaults to '|'\n    delimiter: '|',\n    // The aria-label given to the applied filters bar. Defaults to 'Filters applied to this search:'.\n    labelText: 'Filters applied to this search:',\n    // The aria-label given to the removable filter buttons.\n    removableLabelText: 'Remove this filter'\n  }\n})\n```\n\n## Vertical Results Count Component\n\nThe results count component displays the current results count on a vertical page.\n\n```js\nANSWERS.addComponent('VerticalResultsCount', {\n  container: '.results-count-container',\n  noResults: {\n    // Optional, whether the results count should be visible when displaying no results.\n    // Defaults to false.\n    visible: false\n  }\n});\n```\n\n## Cards\n\nCards are used in Universal/Vertical Results for configuring the UI for a result on a per-item basis.\n\nCards take in a dataMappings attribute, which contains configuration for the card, and a callsToAction\nattribute, which contains config for any callToAction buttons in the card.\n\ncallsToAction config is common throughout all cards, whereas different cards such as Standard vs BigImage\nhave specialized configuration depending on the card. See [Calls To Action](#Calls-To-Action)\n\nThere are three built-in cards, the [Standard Card](#Standard-Card), the [Accordion Card](#Accordion-Card)\nand [Legacy Card](#Legacy-Card).\n\n## Calls To Action\n\ncallsToActions are specified as either an array of CTA configs, or a function that returns\nan array of CTA configs. An array of CTA configs is an object of either static config options\nor functions that return the desired config option.\n\nExamples are detailed below.\n\nNote: A CTA without both a label and icon will not be rendered.\n\n1. an array of static CTA config objects\n\n```js\nconst callsToAction = [{\n  // Label below the CTA icon, default null\n  label: 'cta label',\n  // Icon name for the CTA that is one of the built-in icons, defaults to undefined (no icon). If your icon\n  // is not recognized it will default to 'star'.\n  icon: 'star',\n  // URL to a custom icon for the cta. This takes priority over icon if both are present, default is\n  // no icon url.\n  iconUrl: 'https://urltomyicon.com/customicon.gif',\n  // Click through url for the icon and label\n  // Note, a protocol like https:// is required here.\n  url: 'https://yext.com',\n  // Analytics event that should fire, defaults to 'CTA_CLICK'. Other events outlined in the Analytics section.\n  analytics: 'CTA_CLICK',\n  // The target attribute for the CTA link, defaults to '_blank'. To open in a new window use '_blank'\n  target: '_blank',\n  // The eventOptions needed for the event to fire. Either a valid json string, an object, or a function that\n  // takes in the result data response.\n  // By default, if no event options are specified the SDK will try to add verticalKey, entityId, and searcher options\n  // to the analytics event.\n  eventOptions: result =\u003e {\n    return {\n      // The vertical key for the CTA. If unspecified, this defaults to the vertical key this cta is a part of\n      verticalKey: 'people',\n      // The entity id of the result this cta is a part of, defaults to the entityId field in Knowledge Graph\n      entityId: result.id,\n      // If the CTA is inside a vertical search, defaults to the value \"VERTICAL\",\n      // if is inside a universal search, defaults to the value \"UNIVERSAL\"\n      searcher: 'VERTICAL'\n    };\n  }\n}]\n```\n\n2. as a function that returns a cta config object.\nNOTE: we do not allow multiple nested functions, to avoid messy user configurations.\n\n```js\nconst callsToAction = item =\u003e [{\n  label: item._raw.name,\n  url: 'https://yext.com',\n  analyticsEventType: 'CTA_CLICK',\n  target: '_blank',\n  icon: 'briefcase',\n  eventOptions: `{ \"verticalKey\": \"credit-cards\", \"entityId\": \"${item._raw.id}\", \"searcher\":\"UNIVERSAL\", \"ctaLabel\": \"cards\"}`\n}, {\n  label: 'call now',\n  url: 'https://maps.google.com',\n  analyticsEventType: 'CTA_CLICK',\n  target: '_blank',\n  icon: 'phone',\n  eventOptions: `{ \"verticalKey\": \"credit-cards\", \"entityId\": \"${item._raw.id}\", \"searcher\": \"UNIVERSAL\", \"ctaLabel\": \"cards\"}`\n}]\n```\n\n3. Each individual field in a CTA config can also be a function that operates on the result item.\n\n```js\nconst callsToAction = item =\u003e [{\n  label: item =\u003e item._raw.name,\n  url: 'https://yext.com',\n  analyticsEventType: 'CTA_CLICK',\n  target: '_self',\n  icon: 'briefcase',\n  eventOptions: `{ \"verticalKey\": \"credit-cards\", \"entityId\": \"${item._raw.id}\", \"searcher\": \"UNIVERSAL\", \"ctaLabel\": \"cards\"}`\n}]\n```\n\ncallsToActions can then be included in a card object like so:\n\n```js\nANSWERS.addComponent('VerticalResults', {\n  /* ...other vertical results config... */\n  card: {\n    /* ...other card config...*/\n    callsToAction: item =\u003e [{\n      label: item =\u003e item._raw.name,\n      url: 'https://yext.com',\n    }]\n  }\n  /* ...other vertical results config... */\n})\n```\n\n## Data Mappings\n\nThe dataMappings config option define how a card's attributes, such as title and details, will be rendered.\nThey can be configured either through a function that returns a dataMappings object\nor a static dataMappings object.\n\nEach attribute of a dataMappings object is also either a function or a static value.\n\nBelow is an example of dataMappings as function.\n\n```js\nANSWERS.addComponent('VerticalResults', {\n  /* ...other vertical results config... */\n  card: {\n    /* ...other card config...*/\n    dataMappings: item =\u003e ({\n      title: item.name,\n      subtitle: `Department: ${item.name} `,\n      details: item.description,\n      image: item.headshot ? item.headshot.url : '',\n      url: 'https://yext.com',\n      showMoreLimit: 500,\n      showMoreText: \"show more\",\n      showLessText: \"put it back\",\n      target: '_blank'\n    })\n  }\n  /* ...other vertical results config... */\n})\n```\n\nAnd below is an example of dataMappings as an object with functions inside it.\nYou can use both static attributes and function attributes together.\n\n```js\nANSWERS.addComponent('VerticalResults', {\n  /* ...other vertical results config... */\n  card: {\n    /* ...other card config...*/\n    dataMappings: {\n      title: item =\u003e item.name,\n      subtitle: item =\u003e `Department: ${item.name} `,\n      details: item =\u003e item.description,\n      image: item =\u003e item.headshot ? item.headshot.url : '',\n      url: 'https://yext.com',\n      showMoreLimit: 500,\n      showMoreText: 'show more',\n      showLessText: 'put it back',\n      target: '_blank'\n    }\n  }\n  /* ...other vertical results config... */\n})\n```\n\n\n## Standard Card\n\nThe data mappings for a Standard Card has these attributes\n\n```js\nconst dataMappings = item =\u003e {\n  return {\n    // Title for the card, defaults to the name of the entity\n    title: item.title,\n    // Subtitle, defaults to null\n    subtitle: `Department: ${item.name} `,\n    // Details, defaults to the entity's description\n    details: item.description,\n    // Image to display, defaults to null\n    image: item.headshot ? item.headshot.url : '',\n    // Url for the title/subtitle, defaults to the entity's website url\n    // Note, a protocol like https://yext.com is required, as opposed to just yext.com\n    url: item.link || item.website,\n    // Character limit to hide remaining details and display a show more button, defaults to no limit.\n    showMoreLimit: 350,\n    // Text for show more button, defaults to 'Show More'\n    showMoreText: 'show more',\n    // Text for show less button, defaults to 'Show Less'\n    showLessText: 'put it back',\n    // The target attribute for the title link, defaults to '_self'. To open in a new window use '_blank'\n    target: '_blank',\n    // Whether to show the ordinal of this card in the results, i.e. first card is 1 second card is 2,\n    // defaults to false\n    showOrdinal: false,\n    // A tag to display on top of an image, always overlays the image, default no tag\n    tagLabel: 'On Sale!'\n  };\n}\n```\n\n## Accordion Card\n\nThe data mappings for an Accordion Card has these attributes\n\n```js\nconst dataMappings = item =\u003e {\n  return {\n    // Title for the card, defaults to the name of the entity\n    title: item.title,\n    // Subtitle, defaults to null\n    subtitle: `Department: ${item.name} `,\n    // Details, defaults to the entity's description\n    details: item.description,\n    // Whether the first Accordion Card shown in vertical/universal results should be open on page load, defaults to false\n    expanded: false\n  };\n}\n```\n\n## Legacy Card\n\nThe Legacy Card is very similar to the Standard Card, but with the legacy DOM structure and class names\nfrom before v0.13.0. New users should not use the Legacy Card; instead, use the Standard Card. Features\nadded after v0.13.0 may not work with the Legacy Card.\n\nThe data mappings for a legacy card has these attributes\n\n```js\nconst dataMappings = item =\u003e {\n  return {\n    // Title for the card, defaults to the name of the entity\n    title: item.title,\n    // Subtitle, defaults to null\n    subtitle: `Department: ${item.name} `,\n    // Details, defaults to the entity's description\n    details: item.description,\n    // Image to display, defaults to null\n    image: item.headshot ? item.headshot.url : '',\n    // Url for the title/subtitle, defaults to the entity's website url\n    url: item.link || item.website,\n    // The target attribute for the title link, defaults to '_self'. To open in a new window use '_blank'\n    target: '_blank',\n    // Whether to show the ordinal of this card in the results, i.e. first card is 1 second card is 2,\n    // defaults to false\n    showOrdinal: false\n  };\n}\n```\n\n## Pagination Component\n\nThis component is only for Vertical pages.\n\nThe Pagination component allows users to page through vertical search results.\n\n```html\n\u003cdiv class=\"pagination-container\"\u003e\u003c/div\u003e\n```\n\n```js\nANSWERS.addComponent('Pagination', {\n  // Required, the selector for the container element where the component will be injected\n  container: '.pagination-component',\n  // Required*, the vertical for pagination, *if omitted, will fall back to the search base config\n  verticalKey: 'verticalKey',\n  // Optional, the maximum number of pages visible to non-mobile users. Defaults to 1.\n  maxVisiblePagesDesktop: 1,\n  // Optional, the maximum number of pages visible to mobile users. Defaults to 1.\n  maxVisiblePagesMobile: 1,\n  // Optional, ensure that the page numbers for first and last page are always shown. Not recommended to use with showFirstAndLastButton. Defaults to false.\n  pinFirstAndLastPage: false,\n  // Optional, display double-arrows allowing users to jump to the first and last page of results. Defaults to true.\n  showFirstAndLastButton: true,\n  // Optional, label for a page of results. Defaults to 'Page'.\n  pageLabel: 'Page',\n  // Optional, configuration for the pagination behavior when a query returns no results\n  noResults: {\n    // Optional, whether pagination should be visible when displaying no results.\n    // Defaults to false.\n    visible: false\n  },\n  // Function invoked when a user clicks to change pages. By default, scrolls the user to the top of the page.\n  onPaginate: (newPageNumber, oldPageNumber, totalPages) =\u003e {},\n  // DEPRECATED, please use showFirstAndLastButton instead.\n  // Display a double arrow allowing users to jump to the first page of results. Defaults to showFirstAndLastButton.\n  showFirst: true,\n  // DEPRECATED, please use showFirstAndLastButton instead.\n  // Display a double arrow allowing users to jump to the last page of results. Defaults to showFirstAndLastButton.\n  showLast: true,\n});\n```\n\n## FilterBox Component\n\nThis component is only for Vertical pages.\n\nThe FilterBox component shows a list of filters to apply to a search.\n\n```html\n\u003cdiv class=\"filters-container\"\u003e\u003c/div\u003e\n```\n\n```js\nANSWERS.addComponent('FilterBox', {\n  // Required, the selector for the container element where the component will be injected\n  container: '.filters-container',\n  // Required, list of filter component configurations\n  filters: [\n    {\n      type: 'FilterOptions',\n      control: 'multioption',\n      options: [\n        {\n          label: 'Open Now',\n          field: 'c_openNow',\n          value: true\n        },\n        {\n          label: 'Dog Friendly',\n          field: 'c_dogFriendly',\n          value: true\n        },\n        {\n          label: 'Megastores',\n          field: 'c_storeType',\n          value: 'Megastore'\n        }\n      ]\n    }\n  ],\n  // Optional, title to display above the filter\n  title: 'Filters',\n  // Optional, show number of results for each filter\n  showCount: true,\n  // Optional, execute a new search whenever a filter selection changes. If true, the Apply and Reset buttons will not display\n  searchOnChange: false,\n  // Optional, show a reset button per filter group, this will only display if searchOnChange is false\n  resetFilter: false,\n  // Optional, the label to use for the reset button above, this will only display if searchOnChange is false\n  resetFilterLabel: 'reset',\n  // Optional, show a reset-all button for the filter control. Defaults to displaying a reset button if searchOnChange is false.\n  resetFilters: true,\n  // Optional, the label to use for the reset-all button above, this will only display if resetFilters is true.\n  resetFiltersLabel: 'reset-all',\n  // Optional, allow collapsing excess filter options after a limit\n  showMore: true,\n  // Optional, the max number of filter to show before collapsing extras\n  showMoreLimit: 5,\n  // Optional, the label to show for displaying more filter\n  showMoreLabel: 'show more',\n  // Optional, the label to show for displaying less filter\n  showLessLabel: 'show less',\n  // Optional, allow expanding and collapsing entire groups of filters\n  expand: true,\n  // Optional, show the number of applied filter when a group is collapsed\n  showNumberApplied: true,\n  // Optional, the label to show on the apply button, this will only display if searchOnChange is false\n  applyLabel: 'apply',\n  // Optional, whether or not this filterbox contains dynamic filters, default false\n  isDynamic: true\n});\n```\n\n## Facets Component\n\nThis component is only for Vertical pages.\n\nThe Facets component displays filters relevant to the current search, configured on the server, automatically. The Facets component will be hidden when a query returns no results. The selected options in a facets component will float to the top.\n\n```html\n\u003cdiv class=\"facets-container\"\u003e\u003c/div\u003e\n```\n\n```js\nANSWERS.addComponent('Facets', {\n  // Required, the selector for the container element where the component will be injected\n  container: '.facets-container',\n  // Optional, title to display above the facets\n  title: 'Filters',\n  // Optional, show number of results for each facet\n  showCount: true,\n  // Optional, execute a new search whenever a facet selection changes\n  searchOnChange: false,\n  // Optional, show a reset button per facet group\n  resetFacet: false,\n  // Optional, the label to use for the reset button above\n  resetFacetLabel: 'reset',\n  // Optional, show a reset-all button for the facets control. Defaults to showing a reset-all button if searchOnChange is false.\n  resetFacets: true,\n  // Optional, the label to use for the reset-all button above\n  resetFacetsLabel: 'reset-all',\n  // Optional, allow collapsing excess facet options after a limit\n  showMore: true,\n  // Optional, the max number of facets to show before collapsing extras\n  showMoreLimit: 5,\n  // Optional, the label to show for displaying more facets\n  showMoreLabel: 'show more',\n  // Optional, the label to show for displaying less facets\n  showLessLabel: 'show less',\n  // Optional, allow expanding and collapsing entire groups of facets\n  expand: true,\n  // Optional, show the number of applied facets when a group is collapsed\n  showNumberApplied: true,\n  // Optional, the placeholder text used for the filter option search input\n  placeholderText: 'Search here...',\n  // Optional, if true, display the filter option search input\n  searchable: false,\n  // Optional, the form label text for the search input, defaults to 'Search for a filter option'\n  searchLabelText: 'Search for a filter option',\n  // Optional, a transform function which is applied to an array of facets\n  // See the \"Transforming Facets\" section below for more info\n  transformFacets: (facets, config =\u003e facets),\n  // DEPRECATED, please use transformFacets instead. This option is disabled if transformFacets is supplied\n  // Optional, field-specific overrides for a filter\n  fields: {\n    'c_customFieldName':  { // Field id to override e.g. c_customFieldName, builtin.location\n      // Optional, the placeholder text used for the filter option search input\n      placeholderText: 'Search here...',\n      // Optional, show a reset button per facet group\n      showReset: false,\n      // Optional, the label to use for the reset button above\n      resetLabel: 'reset',\n      // Optional, if true, display the filter option search input\n      searchable: false,\n      // Optional, the form label text for the search input, defaults to 'Search for a filter option'\n      searchLabelText: 'Search for a filter option',\n      // Optional, control type, singleoption or multioption\n      control: 'singleoption',\n      // Optional, override the field name for this facet\n      label: 'My custom field'\n      // Optional, allow collapsing excess facet options after a limit\n      showMore: true,\n      // Optional, the max number of facets to show before collapsing extras\n      showMoreLimit: 5,\n      // Optional, the label to show for displaying more facets\n      showMoreLabel: 'show more',\n      // Optional, the label to show for displaying less facets\n      showLessLabel: 'show less',\n      // Optional, allow expanding and collapsing entire groups of facets\n      expand: true,\n      // Optional, callback function for when a facet is changed\n      onChange: function() { console.log('Facet changed'); },\n      // Optional, the selector used for options in the template, defaults to '.js-yext-filter-option'\n      optionSelector: '.js-yext-filter-option',\n    }\n  },\n  // Optional, the label to show on the apply button\n  applyLabel: 'apply'\n});\n```\n\n### Transforming Facets\n\nThe `transformFacets` option of the Facets component allows facets data to be fully customized. The function takes in and returns an array of the search-core DisplayableFacet which is described [here](https://github.com/yext/search-core/blob/master/docs/search-core.displayablefacet.md). The function also has access to the Facets config as the second parameter.\n\nHere's an example of using this option to customize a boolean facet.\n\n```js\ntransformFacets: facets =\u003e {\n  return facets.map(facet =\u003e {\n    const options = facet.options.map(option =\u003e {\n      let displayName = option.displayName;\n      if (facet.fieldId === 'c_acceptingNewPatients') {\n        if (option.value === false) { displayName = \"Not Accepting Patients\"; }\n        if (option.value === true) { displayName = \"Accepting Patients\"; }\n      }\n      return Object.assign({}, option, { displayName });\n    });\n    return Object.assign({}, facet, { options });\n  });\n},\n```\n\n## FilterSearch Component\n\nThe FilterSearch component provides a text input box for users to type a query and select a preset matching filter. When a filter is selected, a vertical search is performed, and the filter and query are stored in the url. If multiple FilterSearch components are on the page, the search will include all selected filters across all of the components.\n\n```html\n\u003cdiv class=\"filter-search-container\"\u003e\u003c/div\u003e\n```\n\n```js\nANSWERS.addComponent('FilterSearch', {\n  // Required, the selector for the container element where the component will be injected\n  container: '.filter-search-container',\n  // Required\n  verticalKey: '\u003cVERTICAL_KEY\u003e',\n  // Required, the search parameters for autocompletion\n  searchParameters: {\n    // List of fields to query for\n    fields: [{\n      // Field id to query for e.g. c_customFieldName, builtin.location\n      fieldId: 'builtin.location',\n      // Entity type api name e.g. healthcareProfessional, location, ce_person\n      entityTypeId: 'ce_person',\n    }],\n    // Optional, if true, sections search results by search filter, default false\n    sectioned: false\n  },\n  // Optional, no default\n  placeholderText: 'Start typing...',\n  // Optional, if true, the selected filter is saved and used for the next search,\n  // but does not trigger a search itself. Defaults to false.\n  storeOnChange: true,\n  // Optional, defaults to native form node within container\n  formSelector: '.js-form',\n  // Optional, the input element used for searching and wires up the keyboard interaction\n  inputEl: '.js-query',\n  // Optional, provided to the template as a data point\n  title: 'title',\n  // Optional, the search text used for labeling the input box, also provided to template\n  searchText: 'What do you want to search',\n  // Optional, the query text to show as the first item for auto complete\n  promptHeader: 'Header',\n  // Optional, auto focuses the input box if set to true, default false\n  autoFocus: true,\n  // Optional, redirect search query to url\n  redirectUrl: 'path/to/url',\n  // Optional, the query displayed on load. Defaults to the query stored in the url (if any).\n  query: 'Green Ice Cream Flavor',\n  // Optional, the filter for filtersearch to apply on load, defaults to the filter stored in the url (if any).\n  // An example filter is shown below. For more information see the filter section of\n  // https://developer.yext.com/docs/api-reference/#operation/KnowledgeApiServer.listEntities\n  filter: {\n    c_iceCreamFlavors: {\n      $eq: 'pistachio'\n    }\n  }\n})\n```\n\n## Filter Components\n\nFilter components can be used in a FilterBox or on their own to affect a search.\n\n### FilterOptions\n\nFilterOptions displays a set of filters with either checkboxes or radio buttons.\nAs a user interacts with FilterOptions, information on which options are selected\nis stored in the url. Returning to that same url will load the page with those saved\noptions already selected.\n\n```html\n\u003cdiv class=\"filter-container\"\u003e\u003c/div\u003e\n```\n\n```js\nANSWERS.addComponent('FilterOptions', {\n  // Required, the selector for the container element where the component will be injected\n  container: '.filter-container',\n  // Required, control type: 'singleoption' or 'multioption'\n  control: 'singleoption',\n  // The type of options to filter by, either 'STATIC_FILTER' or 'RADIUS_FILTER'.\n  // Defaults to 'STATIC_FILTER'.\n  optionType: 'STATIC_FILTER',\n  // Required, list of options\n  options: [\n    /** Depends on the above optionType, either 'STATIC_FILTER' or 'RADIUS_FILTER', see below. **/\n  ],\n  // Optional, if true, the filter value is saved on change and sent with the next search. Defaults to true.\n  storeOnChange: true,\n  // Optional, the selector used for options in the template, defaults to '.js-yext-filter-option'\n  optionSelector: '.js-yext-filter-option',\n  // Optional, if true, show a reset button\n  showReset: false,\n  // Optional, the label to use for the reset button, defaults to 'reset'\n  resetLabel: 'reset',\n  // Optional, allow collapsing excess filter options after a limit, defaults to true\n  showMore: true,\n  // Optional, the max number of filter options to show before collapsing extras, defaults to 5\n  showMoreLimit: 5,\n  // Optional, the label to show for displaying more options, defaults to 'show more'\n  showMoreLabel: 'show more',\n  // Optional, the label to show for displaying less options, defaults to 'show less'\n  showLessLabel: 'show less',\n  // Optional, allow expanding and collapsing the filter, defaults to true\n  showExpand: true,\n  // Optional, show the number of applied options when a group is collapsed, defaults to true\n  showNumberApplied: true,\n  // Optional, the callback function to call when changed\n  onChange: function() {},\n  // Optional, the label to be used in the legend, defaults to 'Filters'\n  label: 'Filters',\n  // Optional, the placeholder text used for the filter option search input\n  placeholderText: 'Search here...',\n  // Optional, if true, display the filter option search input\n  searchable: false,\n  // Optional, the form label text for the search input, defaults to 'Search for a filter option'\n  searchLabelText: 'Search for a filter option',\n});\n```\n\nThe options config varies depending on whether the optionType is 'STATIC_FILTER' or 'RADIUS_FILTER'.\nA STATIC_FILTER allows you to filter on a specified field, while a RADIUS_FILTER allows you to filter\nresults based on their distance from the user.\n\n##### STATIC_FILTER\n\n```js\n{\n  options: [\n    {\n      // Required, the api field to filter on, configured on the Yext platform.\n      field: 'c_openNow',\n      // Required, the value for the above field to filter by.\n      value: true,\n      // Optional, the label to show next to the filter option.\n      label: 'Open Now',\n      // Optional, whether this option will be selected on page load. Selected options stored in the url\n      // take priority over this. Defaults to false.\n      selected: false\n    },\n    {\n      field: 'c_dogFriendly',\n      value: true,\n      label: 'Dog Friendly',\n      selected: true\n    },\n    {\n      field: 'c_storeType',\n      value: 'Megastore',\n      label: 'Megastores'\n    }\n  ]\n}\n```\n\n##### RADIUS_FILTER\n\n```js\n{\n  options: [\n    {\n      // Required, the value of the radius to apply (in meters). If this value is 0, the SDK will not add explicit radius filtering to the request. The backend may still perform its own filtering depending on the query given.\n      value: 8046.72,\n      // Optional, the label to show next to the filter option.\n      label: '5 miles',\n      // Optional, whether this option will be selected on page load. Selected options stored in the url\n      // take priority over this. Defaults to false.\n      selected: false\n    },\n    {\n      value: 16093.4,\n      label: '10 miles',\n      selected: true\n    },\n    {\n      value: 40233.6,\n      label: '25 miles'\n    },\n    {\n      value: 80467.2,\n      label: '50 miles'\n    },\n    {\n      value: 0,\n      label: \"Do not filter by radius\"\n    }\n  ],\n}\n```\n\n### RangeFilter\n\nDisplays two numeric inputs for selecting a number range.\n\n```html\n\u003cdiv class=\"range-filter-container\"\u003e\u003c/div\u003e\n```\n\n```js\nANSWERS.addComponent('RangeFilter', {\n  // Required, the selector for the container element where the component will be injected\n  container: '.range-filter-container',\n  // Required, the API name of the field to filter on\n  field: 'outdoorPoolCount',\n  // Optional, title to display for the range control, defaults to empty legend\n  title: 'Number of Outdoor Pools',\n  // Optional, the label to show next to the min value, defaults to no label\n  minLabel: 'At Least',\n  // Optional, the placeholder text for the min value, defaults to 'Min'\n  minPlaceholderText: 'Min',\n  // Optional, the label to show next to the max value, defaults to no label\n  maxLabel: 'Not More Than',\n  // Optional, the placeholder text for the max value, defaults to 'Max'\n  maxPlaceholderText: 'Max',\n  // Optional, the initial min value to show, defaults to 0. Set this to null to clear the value.\n  initialMin: 1,\n  // Optional, the initial max value to show, defaults to 10. Set this to null to clear the value.\n  initialMax: 5,\n  // Optional, the callback function to call when changed\n  onChange: function() {}\n});\n```\n\n### DateRangeFilter\n\nDisplays two date inputs for selecting a range of dates.\n\n```html\n\u003cdiv class=\"date-range-filter-container\"\u003e\u003c/div\u003e\n```\n\n```js\nANSWERS.addComponent('DateRangeFilter', {\n  // Required, the selector for the container element where the component will be injected\n  container: '.date-range-filter-container',\n  // Required, the API name of the field to filter on\n  field: 'time.start',\n  // Optional, title to display for the range, defaults to empty legend\n  title: 'Event Start Date',\n  // Optional, the label to show next to the min date, defaults to no label\n  minLabel: 'Earliest',\n  // Optional, the label to show next to the max date, defaults to no label\n  maxLabel: 'Latest',\n  // Optional, the initial min date to show in yyyy-mm-dd format, defaults to today. Set this to null to clear the value.\n  initialMin: '2019-08-01',\n  // Optional, the initial max date to show in yyyy-mm-dd format, defaults to today. Set this to null to clear the value.\n  initialMax: '2019-09-01',\n  // Optional, whether to store the filter on change to input\n  storeOnChange: true,\n  // Optional, if true, this filter represents an exclusive range, rather than an inclusive one, defaults to false\n  isExclusive: false,\n  // Optional, the callback function to call when changed\n  onChange: function() {}\n});\n```\n\n### GeoLocationFilter\n\nDisplays a \"Use My Location\" button that filters results to a radius around the user's current position.\n\n```html\n\u003cdiv class=\"geolocation-filter-container\"\u003e\u003c/div\u003e\n```\n\nFor all optional config in the example, unless otherwise specified, the default is the example value.\n\n```js\nANSWERS.addComponent('GeoLocationFilter', {\n  // Required, the selector for the container element where the component will be injected\n  container: '.geolocation-filter-container',\n  // Optional, the vertical key to use\n  verticalKey: 'verticalKey',\n  // Optional, radius around the user, in miles, to find results, default 50\n  radius: 50,\n  // Optional, the text to show when enabled\n  enabledText: 'Disable My Location',\n  // Optional, the text to show ehn loading the user's location\n  loadingText: 'Loading',\n  // Optional, The label to show when unable to get the user's location\n  errorText: 'Unable To Use Location',\n  // Optional, CSS selector of the button\n  buttonSelector: '.js-yxt-GeoLocationFilter-button',\n  // Optional, Css selector of the query input\n  inputSelector: '.js-yxt-GeoLocationFilter-input',\n  // Optional, if true, triggers a search on each change to a filter, default false\n  searchOnChange: true,\n  // Optional, the icon url to show in the geo button\n  geoButtonIcon: 'path/to/url',\n  // Optional, the alt text to use with the geo button's icon\n  geoButtonIconAltText: 'Use My Location',\n  // Optional, the text to show in the geo button\n  geoButtonText: 'Use my location',\n  // Optional, Search parameters for the geolocation autocomplete\n  searchParameters: {\n    // List of fields to query for\n    fields: [{\n      // Field id to query for e.g. c_customFieldName, builtin.location\n      fieldId: 'builtin.location',\n      // Entity type api name e.g. healthcareProfessional, location, ce_person\n      entityTypeId: 'ce_person',\n      // Optional, if true sections search results by search filter, default false\n      sectioned: false,\n    }]\n  },\n  // Optional, options to pass to the geolocation api, which is used to fetch the user's current location.\n  // https://developer.mozilla.org/en-US/docs/Web/API/PositionOptions\n  geolocationOptions: {\n    // Optional, whether to improve accuracy at the cost of response time and/or power consumption, defaults to false.\n    enableHighAccuracy: false,\n    // Optional, the maximum amount of time (in ms) a geolocation call is allowed to take before defaulting, defaults to 6 seconds.\n    timeout: 6000,\n    // Optional, the maximum amount of time (in ms) to cache a geolocation call, defaults to 5 minutes.\n    maximumAge: 300000,\n  },\n  // Optional, options for an alert when the geolocation call fails.\n  geolocationTimeoutAlert: {\n    // Optional, whether to display a window.alert() on the page, defaults to false.\n    enabled: false,\n    // Optional, the message in the alert. Defaults to the below\n    message: \"We are unable to determine your location\"\n  }\n});\n```\n\n## Applied Filters Component\n\nThe Applied Filters Component displays your currently applied filters as a row of text tags, labeled\nby filter display value. If the \"removable\" config option is set to true, these text tags will instead\nbe \"removable filters\", which, when clicked, will remove the clicked filter from the search.\nOnly intended for vertical pages.\n\n```js\nANSWERS.addComponent('AppliedFilters', {\n  container: '.applied-filters-container',\n  // Optional, The vertical key of your search. Defaults to the vertical key specified in the search config.\n  verticalKey: 'aVerticalKey',\n  // Optional, Whether to display the field name of each group of applied filters. e.g. \"Location: Virginia, New York\" vs just \"Virginia, New York\". Defaults to false.\n  showFieldNames: false,\n  // Optional, This is list of filters that should not be displayed. Defaults to hiding ['builtin.entityType'].\n  hiddenFields: ['builtin.entityType'],\n  // Optional, Whether or not the displayed filters should be removable filters, or just simple text tags. Defaults to false (text tags).\n  removable: false,\n  // Optional, The character that separates each group of filters (grouped by field name). Defaults to '|'.\n  delimiter: '|',\n  // Optional, The aria-label given to the component. Defaults to 'Filters applied to this search:'.\n  labelText: 'Filters applied to this search:',\n  // Optional, The aria-label given to the removable filters. Defaults to 'Remove this filter'.\n  removableLabelText: 'Remove this filter'\n});\n```\n\n## Navigation Component\n\nThe Navigation Component adds a dynamic experience to your pages navigation experience.\n\nWhen using multiple vertical searches in a universal search, the navigation ordering will be automatically updated based on the search results. By default, tabs that do not fit in the container will go inside a dropdown menu.\n\nVertical configurations should be provided the ANSWERS.init's `verticalPages` configuration. Find more info in the [Vertical Pages Configuration](#vertical-pages-configuration) section.\n\n\n```html\n\u003cdiv class=\"navigation-container\"\u003e\u003c/nav\u003e\n```\n\n```js\nANSWERS.addComponent('Navigation', {\n  // Required, the selector for the container element where the component will be injected\n  container: '.navigation-container',\n  // Optional, controls if navigation shows a scroll bar or dropdown for mobile. Options are COLLAPSE and INNERSCROLL\n  mobileOverflowBehavior: 'COLLAPSE',\n  // Optional, the aria-label to set on the navigation, defaults to 'Search Page Navigation'\n  ariaLabel: 'Search Page Navigation',\n  // Optional, the label to display on the dropdown menu button when it overflows, defaults to 'More'\n  overflowLabel: 'More',\n  // Optional, name of the icon to show on the dropdown button instead when it overflows\n  overflowIcon: null,\n})\n```\n\n## QA Submission Component\n\nThe QA Submission component provides a form for submitting a QA question,\nwhen a search query is run.\n\n```html\n\u003cdiv class=\"question-submission-container\"\u003e\u003c/div\u003e\n```\n\n```js\nANSWERS.addComponent('QASubmission', {\n  // Required, the selector for the container element where the component will be injected\n  container: '.question-submission-container',\n  // Required. Set this to the Entity ID of the organization entity in the Knowledge Graph\n  entityId: 123,\n  // Required. Defaults to ''\n  privacyPolicyUrl: 'https://mybiz.com/policy',\n  // Optional, defaults to native form node within container\n  formSelector: '.js-form',\n  // Optional, ;abel for name input\n  nameLabel: 'Name',\n  // Optional, label for email input\n  emailLabel: 'Email',\n  // Optional, label for question input\n  questionLabel: 'Question',\n  // Optional, title displayed for the form\n  sectionTitle: 'Ask a question',\n  // Optional, teaser displayed for the form, next to the title\n  teaser: 'Can\\'t find what you’re looking for? Ask a question below.',\n  // Optional, description for the form\n  description: 'Enter your question and contact information, and we\\'ll get back to you with a response shortly.'\n  // Optional, text before the privacy policy link\n  privacyPolicyText: 'By submitting my email address, I consent to being contacted via email at the address provided.',\n  // Optional, label for the privacy policy url\n  privacyPolicyUrlLabel: 'Learn more here.',\n  // Optional, error message displayed when the privacy policy is not selected\n  privacyPolicyErrorText: '* You must agree to the privacy policy to submit feedback.',\n  // Optional, error message displayed when an invalid email is not submitted\n  emailFormatErrorText: '* Please enter a valid email address.'\n  // Optional, placeholder displayed in all required fields\n  requiredInputPlaceholder: '(required)',\n  // Optional, confirmation displayed once a question is submitted\n  questionSubmissionConfirmationText: 'Thank you for your question!',\n  // Optional, label displayed on the button to submit a question\n  buttonLabel: 'Submit',\n  // Optional, set this to whether or not the form is expanded by default when a user arrives on the  page\n  expanded: true,\n  // Optional, error message displayed when there is an issue with the QA Submission request\n  networkErrorText: 'We\\'re sorry, an error occurred.'\n})\n```\n\n## Spell Check Component\n\nThe spell check component shows spell check suggestions/autocorrect.\n\n```html\n\u003cdiv class=\"spell-check-container\"\u003e\u003c/div\u003e\n```\n\n```js\nANSWERS.addComponent('SpellCheck', {\n  // Required, the selector for the container element where the component will be injected\n  container: '.spell-check-container',\n  // Optional, the help text to display when suggesting a query\n  suggestionHelpText: 'Did you mean:',\n})\n```\n\n## Location Bias Component\n\nThe location bias component shows location that used for location bias and allow user to improve accuracy with HTML5 geolocation.\n\n```html\n\u003cdiv class=\"location-bias-container\"\u003e\u003c/div\u003e\n```\n\n```js\nANSWERS.addComponent('LocationBias', {\n  // Required, the selector for the container element where the component will be injected\n  container: '.location-bias-container',\n  // Optional, the vertical key for the search, default null\n  verticalKey: 'verticalKey',\n  // Optional, the element used for updating location\n  updateLocationEl: '.js-locationBias-update-location',\n  // Optional, help text to inform someone their IP was used for location\n  ipAccuracyHelpText: 'based on your internet address',\n  // Optional, help text to inform someone their device was used for location\n  deviceAccuracyHelpText: 'based on your device',\n  // Optional, text used for the button to update location\n  updateLocationButtonText: 'Update your location',\n  // Optional, options to pass to the geolocation api, which is used to fetch the user's current location.\n  // https://developer.mozilla.org/en-US/docs/Web/API/PositionOptions\n  geolocationOptions: {\n    // Optional, whether to improve accuracy at the cost of response time and/or power consumption, defaults to false.\n    enableHighAccuracy: false,\n    // Optional, the maximum amount of time (in ms) a geolocation call is allowed to take before defaulting, defaults to 6 seconds.\n    timeout: 6000,\n    // Optional, the maximum amount of time (in ms) to cache a geolocation call, defaults to 5 minutes.\n    maximumAge: 300000,\n  },\n  // Optional, options for an alert when the geolocation call fails.\n  geolocationTimeoutAlert: {\n    // Optional, whether to display a window.alert() on the page, defaults to false.\n    enabled: false,\n    // Optional, the message in the alert. Defaults to the below\n    message: \"We are unable to determine your location\"\n  }\n})\n```\n\n## Sort Options Component\n\nThe sort options component displays a list of radio buttons that allows users to sort the results of a vertical search. When a query returns no results, the component will not be rendered on the page.\nCurrently, there may be only one sort options component per page.\n\n```html\n\u003cdiv class='sort-options-container'\u003e\u003c/div\u003e\n```\n\n```js\n// note: showExpand and showNumberApplied options are explicitly not included:\n// sorting will always be exposed to the user if added.\nANSWERS.addComponent('SortOptions', {\n  // Required, the selector for the container element where the component will be injected\n  container: '.sort-options-container',\n  // Optional: The label used for the “default” sort (aka sort the order provided by the config), defaults to 'Best Match'\n  defaultSortLabel: 'Best Match',\n  // Required: List of component configurations\n  options: [\n    {\n      // Required: Either FIELD, ENTITY_DISTANCE, or RELEVANCE\n      type: 'FIELD',\n      // Required only if type is FIELD, field name to sort by\n      field: 'c_popularity',\n      // Direction to sort by, either 'ASC' or 'DESC'\n      // Required only if type is FIELD\n      direction: 'ASC',\n      // Required: Label for the sort option's radio button\n      label: 'Popularity',\n    },\n    {\n      type: \"ENTITY_DISTANCE\",\n      label: 'Distance'\n    },\n    {\n      type: 'RELEVANCE',\n      label: 'Relevance'\n    }\n  ],\n  // Required: the vertical key used\n  verticalKey: 'KM',\n  // Optional: the selector used for options in the template, defaults to '.yxt-SortOptions-optionSelector'\n  optionSelector: '.yxt-SortOptions-optionSelector',\n  // Optional: if true, triggers a resorts on each change to the sort options,\n  // if false the component also renders an apply button that applies the sort, defaults to false\n  searchOnChange: false,\n  // Optional: Show a reset button, defaults to false\n  showReset: false,\n  // Optional: The label to use for the reset button, defaults to 'reset'\n  resetLabel: 'reset',\n  // Optional: Allow collapsing excess filter options after a limit, defaults to true\n  // Note: screen readers will not read options hidden by this flag, without clicking show more first\n  showMore: true,\n  // Optional: The max number of filter options to show before collapsing extras, defaults to 5\n  showMoreLimit: 5,\n  // Optional: The label to show for displaying more options, defaults to 'Show more'\n  showMoreLabel: 'Show more',\n  // Optional: The label to show for displaying less options, defaults to 'Show less'\n  showLessLabel: 'Show less',\n  // Optional, the callback function to call when changed, defaults to function() =\u003e {}\n  // runs BEFORE search triggered by searchOnChange if searchOnChange is true\n  onChange: function() {},\n  // Optional, the label to be used in the legend, defaults to 'Sorting'\n  label: 'Sorting',\n  // Optional, the label to be used on the apply button\n  // only appears if searchOnChange is false, defaults to 'Apply'\n  applyLabel: 'Apply'\n});\n```\n\n## Map Component\nThe Map component displays a map with a pin for each result that has Yext display coordinates.\n\n```html\n\u003cdiv class='map-container'\u003e\u003c/div\u003e\n```\n\n```js\nANSWERS.addComponent('Map', {\n  // Required. This is the class of the target HTML element the component will be mounted to\n  container: '.map-container',\n  // Required. Supported map providers include: `google` or `mapBox`, not case-sensitive\n  mapProvider: 'mapBox',\n  // Required*. The API Key used for interacting with the map provider; (*except for Google Maps if provided `clientId`)\n  apiKey: '',\n  // Optional, can be used for Google Maps in place of the API key\n  clientId: '',\n  // Optional, used to determine the language of the map. Defaults to the locale specified in the ANSWERS init.\n  // Refer to the section \"Supported Map Locales\" below for the list of supported locales.\n  locale: 'en',\n  // Optional, determines whether or not to collapse pins at the same lat/lng\n  collapsePins: false,\n  // Optional, the zoom level of the map, defaults to 14\n  zoom: 14,\n  // Optional, the default coordinates to display if there are no results returned used if showEmptyMap is set to true\n  defaultPosition: { lat: 37.0902, lng: -95.7129 },\n  // Optional, determines if an empty map should be shown when there are no results. Defaults to false.\n  showEmptyMap: false,\n  // Optional, callback to invoke when a pin is clicked. The clicked item(s) are passed to the callback\n  onPinClick: null,\n  // Optional, callback to invoke when a pin is hovered. The clicked item(s) are passed to the callback\n  onPinMouseOver: null,\n  // Optional, callback to invoke when a pin is no longer hovered after being hovered. The clicked item(s) are passed to the callback\n  onPinMouseOut: null,\n  // Optional, callback to invoke once the Javascript is loaded\n  onLoaded: function () {},\n  // Optional, configuration for the map's behavior when a query returns no results\n  noResults: {\n    // Optional, whether to display map pins for all possible results when no results are found. Defaults to false.\n    displayAllResults: false,\n    // Optional, whether to display the map when no results are found, taking priority over showEmptyMap. If unset, a map will be visible if showEmptyMap is true OR if displayAllResults is true and alternative results are returned.\n    visible: false\n  },\n  // Optional, the custom configuration override to use for the map markers, function\n  pin: function () {\n    return {\n      icon: {\n        anchor: null, // e.g. { x: 1, y: 1 }\n        svg: null,\n        url: null,\n        scaledSize: null // e.g. { w: 20, h: 20 }\n      },\n      labelType: 'numeric'\n    };\n  },\n  // Optional, an object which contains options which are passed directly to the specified mapProvider.\n  // Refer to the map option api reference for the specified map provider\n  providerOptions: {\n    style: 'mapbox://styles/mapbox/light-v9' // Specifies a custom style for mapbox\n  }\n};\n```\n\n### Supported Map Locales\n\nWhen using MapBox (`mapBox`) as the `mapProvider`, the valid locale options\nare the ones listed here:\n\n+ Arabic: `ar`\n+ Chinese: `zh`\n+ English: `en`\n+ French: `fr`\n+ German: `de`\n+ Japanese: `ja`\n+ Korean: `ko`\n+ Portuguese: `pt`\n+ Russian: `ru`\n+ Spanish: `es`\n\nWhen using Google Maps (`google`) as the `mapProvider`, the valid locale options can be found [here](https://developers.google.com/maps/faq#languagesupport).\n\n## Icon Component\nThe Icon Component will typically be created by other components, but it can be used as a standalone component as well.\n\n```html\n\u003cdiv class='icon-container'\u003e\u003c/div\u003e\n```\n\n```js\nANSWERS.addComponent('IconComponent', {\n  // Required. This is the class of the target HTML element the component will be mounted to.\n  container: '.icon-container',\n  // Optional. Can be used to access an icon defined within the Answers system. See below for default icon names.\n  iconName: 'default',\n  // Optional. Sets the icon to reference an image URL. Overrides icon name.\n  iconUrl: '',\n  // Optional. Adds class names to the icon. Multiple classnames should be space-delimited.\n  classNames: '',\n});\n```\nThe following is a list of names for the icons that are supported by default.\n\n- briefcase\n- calendar\n- callout\n- chevron\n- close\n- directions\n- document\n- elements\n- email\n- gear\n- info\n- kabob\n- light_bulb\n- link\n- magnifying_glass\n- mic\n- office\n- pantheon\n- person\n- phone\n- pin\n- receipt\n- star\n- support\n- tag\n- thumb\n- window\n- yext_animated_forward\n- yext_animated_reverse\n- yext\n\n# Customizing Components\n\n## Using a Custom Renderer\n\nIf you want to use a use your own template language (e.g. soy, mustache, groovy, etc),\nyou should NOT use the template argument. Instead, you can provide a custom render function to the component.\n\n```js\nANSWERS.addComponent('SearchBar', {\n  container: '.search-container',\n  render: function(data) {\n    // Using native ES6 templates -- but you can replace this with soy,\n    // or any other templating language as long as it returns a string.\n    return `\u003cdiv class=\"my-search\"\u003e${data.title}\u003c/div\u003e`\n  }\n})\n```\n\n## Custom Data Formatting\n\nYou can format specific entity fields using `fieldFormatters`.\nThese formatters are applied before the `transformData` step.\n\nEach formatter takes in an object with the following properties :\n- `entityProfileData`\n- `entityFieldValue`\n- `highlightedEntityFieldValue`\n- `verticalId`\n- `isDirectAnswer`\n\nBelow is an example usage.\n```js\nANSWERS.init({\n  apiKey: '\u003cAPI_KEY_HERE\u003e',\n  experienceKey: '\u003cEXPERIENCE_KEY_HERE\u003e',\n  fieldFormatters: {\n    'name': (formatterObject) =\u003e formatterObject.entityFieldValue.toUpperCase(),\n    'description' : (formatterObject) =\u003e formatterObject.highlightedEntityFieldValue\n  }\n});\n```\n\n## Custom Data Transforms\n\nIf you want to mutate the data thats provided to the render/template before it gets rendered,\nyou can use the `transformData` hook.\n\nAll properties and values that you return from here will be accessible from templates.\n\n\n```js\nANSWERS.addComponent('SearchBar', {\n  container: '.search-container',\n  transformData: (data) =\u003e {\n    // Extend/overide the data object\n    return Object.assign({}, data, {\n      title: data.title.toLowerCase()\n    })\n  },\n  render: function(data) {\n    // Using native ES6 templates -- but you can replace this with soy,\n    // or any other templating language as long as it returns a string.\n    return `\u003cdiv class=\"my-search\"\u003e${data.title}\u003c/div\u003e`\n  }\n})\n```\n\n## Using a Custom Template for a Component\nAll component templates are written using [Handlebars templates](https://handlebarsjs.com/).\n\nIt's easy to override these templates with your own templates.\nKeep in mind, that you must provide valid handlebars syntax here.\n\n```js\n// Use handlebars syntax to create a template string\nlet customTemplate = `\u003cdiv class=\"my-search\"\u003e{{title}}\u003c/div\u003e`\n\nANSWERS.addComponent('SearchBar', {\n  container: '.search-container',\n  template: customTemplate\n})\n```\n\nThe SDK also offers an `ANSWERS.registerTemplate` function. This will map\na template string to an entry in the Answers handlebars renderer.\n\n```js\n  /**\n   * Compile and add a template\n   * @param {string} templateName The unique name for the template\n   * @param {string} template The handlebars template string\n   */\n  registerTemplate (templateName, template)\n```\n\nThe default handlebars renderer uses a mapping from template name strings to\nhandlebars template strings. If, while trying to register a template, the\ntemplate name does not exist, a new template entry is created. If the name\nalready exists, the current template for the template name is overriden. This\nallows you override default template names.\n\nFor example:\n```js\n  // override current SpellCheck template\n  ANSWERS.registerTemplate(\n    'search/spellcheck',\n    '\u003cdiv class=\"Mine\"\u003eDid you mean {{correctedQuery}}?\u003c/div\u003e'\n  );\n\n  // create new Card template\n  ANSWERS.registerTemplate(\n    'cards/custom',\n    '\u003cp\u003eCard content\u003c/p\u003e'\n  );\n```\n\n## Creating Custom Components\nYou can create custom Answers components with the same power of the builtin components. First, create\na subtype of ANSWERS.Component and register it.\n\nFor ES6:\n```js\nclass MyCustomComponent extends ANSWERS.Component {\n  constructor (config) {\n    super(config);\n    this.myProperty = config.myProperty;\n  }\n\n  static defaultTemplateName () {\n    return 'default';\n  }\n\n  static areDuplicateNamesAllowed () {\n    return false;\n  }\n\n  static get type () {\n    return 'MyCustomComponent';\n  }\n}\nANSWERS.registerComponentType(MyCustomComponent); // Register the component with the library\n```\n\nFor ES5:\n```js\nfunction MyCustomComponent (config) {\n  ANSWERS.Component.call(this, config);\n\n  this.myProperty = config.myProperty;\n}\n\nMyCustomComponent.prototype = Object.create(ANSWERS.Component.prototype);\nMyCustomComponent.prototype.constructor = MyCustomComponent;\nMyCustomComponent.defaultTemplateName = function () { return 'default' };\nMyCustomComponent.areDuplicateNamesAllowed = function () { return false };\nObject.defineProperty(MyCustomComponent, 'type', { get: function () { return 'MyCustomComponent' } });\n\nANSWERS.registerComponentType(MyCustomComponent); // Register the component with the library\n```\n\nNow you can use your custom component like any built-in component:\n\n```js\nANSWERS.addComponent('MyCustomComponent', {\n  container: '.my-component-container',\n  template: `\u003cdiv\u003e{{_config.myProperty}}\u003c/div\u003e`,\n  myProperty: 'my property'\n});\n```\n\n# Extending the Built-in Renderer\n\n## Custom Partials\n\n[Handlebars partials](https://handlebarsjs.com/guide/partials.html) use the\nsame handlebars syntax as templates, but they can be reused and be called\ndirectly from templates or other partials. The ANSWERS object offers an\n`ANSWERS.registerPartial` function for custom partials. This will map a partial \nstring to an entry in the Answers handlebars renderer.\n\n```js\n  /**\n   * Add a partial\n   * @param {string} partialName The unique name for the partial\n   * @param {string} partial The handlebars partial string\n   */\n  registerPartial (partialName, partial)\n```\n\nThe default handlebars renderer uses a mapping from partial name strings to\nhandlebars partial strings. Once registered, this custom partial can be called\nfrom other partials or templates.\n\nFor example,\n```js\n  // create custom partial\n  ANSWERS.registerPartial(\n    'thank-you-message',\n    '\u003cdiv class=\"thanks\"\u003eThank you!\u003c/div\u003e'\n  );\n\n  // use new partial in a template\n  ANSWERS.registerTemplate(\n    'cards/custom',\n    '\u003cp\u003eMain information\u003c/p\u003e {{\u003e thank-you-message }}'\n  );\n```\n\n## Template Helpers\n\nWhen using handlebars templates, Answers ships with a bunch of pre-built template helpers that you can use. You can learn more about them [here](https://github.com/jonschlinkert/template-helpers).\n\nIf you want to register custom template helpers to the handlebars render, you can do so like this:\n```js\nANSWERS.registerHelper('noop', function(options) {\n  return options.fn(this);\n})\n```\n\nYou can learn more about the interface for registering helpers by taking a look at the [Handlebars Block Helpers](https://handlebarsjs.com/block_helpers.html) documentation.\n\n# Analytics\n\nIf a businessId is supplied in the config, Answers will track some basic interaction analytics automatically, such as search bar impressions and Call-To-Action clicks.\n\nIf you would like to add custom analytics on top of the built-in ones, use the following:\n\n## Custom Analytics Using JavaScript\n\nYou may send analytics from external code with the below interface.\n\n```js\n  const event = new ANSWERS.AnalyticsEvent('CUSTOM');\n  event.addOptions({ myData: 'data' });\n  ANSWERS.AnalyticsReporter.report(event)\n```\n\n## Custom Analytics Using Data Attributes\n\nYou may add additional, custom analytic events to templates using certain data attributes. Click analytics can be attached to an element by adding the `data-eventtype` attribute to the element you want to track clicks for. The provided string should be the type of the analytics event. You can optionally include metadata inside the `data-eventoptions` attribute, in a JSON format. Whenever the element is clicked, an analtyics event with that data will be sent to the server.\n\n```html\n\u003cbutton class=\"driving-directions-button\"\n        data-eventtype=\"DRIVING_DIRECTIONS\"\n        data-eventoptions='{\"store\": \"{{store}}\"}'\n\u003e\n    Drive to {{store}}\n\u003c/button\u003e\n```\n\n## Built-In Analytics Events For CTAs\nHere are the possible Event Types for CTAs:\n- TITLE_CLICK\n- CTA_CLICK\n- TAP_TO_CALL\n- ORDER_NOW\n- ADD_TO_CART\n- APPLY_NOW\n- DRIVING_DIRECTIONS\n- VIEW_WEBSITE\n- EMAIL\n- BOOK_APPOINTMENT\n- RSVP\n\nThese types are accepted as the `analytics` attribute in [Calls To Action](#Calls-To-Action).\n\n## Conversion Tracking\n\nBy default, Answers does not perform conversion tracking for analytics. To opt-in to this behavior, use the `setConversionsOptIn` method after initialization:\n\n```js\nANSWERS.init({ ... });\nagreementButton.onclick = function() { ANSWERS.setConversionsOptIn(true); };\n```\n\nYou must also add the following to your HTML:\n\n```html\n\u003cscript src=\"https://assets.sitescdn.net/ytag/ytag.min.js\"\u003e\u003c/script\u003e\n```\n\n## On-Search Analytics\n\nYou can find instructions for configuring on search analytics above in these sections: [onVerticalSearch Configuration](#onverticalsearch-configuration), [onUniversalSearch Configuration](#onuniversalsearch-configuration).\n\n# Rich Text Formatting\n\nThe Answers SDK exposes a `formatRichText` function which translates CommonMark to HTML. This function will\nensure that a Rich Text Formatted value is shown properly on the page. To use this function, call it like so:\n\n```js\nANSWERS.formatRichText(rtfFieldValue, eventOptionsFieldName, targetConfig)\n```\n\nFor instance, this function can be used in the `dataMappings` of a Card to display an RTF attribute. \n\nWhen clicking any link in the resultant HTML, an `AnalyticsEvent` will be fired. If the `eventOptionsFieldName` has been\nspecified, the `eventOptions` will include a `fieldName` attribute with the given value. \n\nThe `targetConfig` parameter dictates where the link is opened: the current window, a new tab, etc. It can have the following forms:\n\n```js\ntargetConfig = { url: '_blank', phone: '_self', email: '_parent' }\ntargetConfig = '_blank'\n```\n\nWhen `targetConfig` is a string, it is assumed that any link, regardless of type, has the specified `target` behavior. This parameter, like `eventOptionsFieldName`, is optional. When not provided, no `target` attribute is supplied to the links.\n\nNote that when using this function, you must ensure that the relevant Handlebars template correctly unescapes the output HTML.\n\n# CSS Variable Styling\n\nThe Answers SDK supports styling specific elements with CSS variables for runtime styling.\n* All sdk variables are exposed in the `:root` ruleset\n* All overridden variables must be included the `:root` ruleset\n* All overrides should be defined after Answers CSS is imported and before ANSWERS.init is called\n* To see available variables, see the scss modules in the SDK\n* For example, to override:\n\n```html\n\u003cstyle\u003e\n  :root {\n    --yxt-font-font-family: sans-serif;\n    --yxt-color-brand-primary: green;\n    --yxt-color-text-primary: #212121;\n    --yxt-searchbar-button-background-color-hover: red;\n    --yxt-nav-border-color: #e9e9e9;\n  }\n\u003c/style\u003e\n```\n\nMost browsers have native css variable support. In legacy browsers,\nwe use the [css-vars-ponyfill](https://github.com/jhildenbiddle/css-vars-ponyfill).\n* The SDK will do automatic resolution of CSS variables on initialization. Variables should be loaded\nbefore initialization. Overrided variables should be loaded after sdk variables are loaded.\n* You can opt-out with the `disableCssVariablesPonyfill` flag in ANSWERS.init.\n* If you opt-out of automatic resolution of variables, you should call ANSWERS.ponyfillCssVariables()\nafter css variables are loaded and before components are added.\n* If you change a css variable value after initialization and wish to see the change in variable\nvalue in a legacy browser, you should call ANSWERS.ponyfillCssVariables() after the value is changed.\n* We support all callback functions, described [here](https://jhildenbiddle.github.io/css-vars-ponyfill/#/?id=onbeforesend)\n\n```js\nANSWERS.ponyfillCssVariables({\n        onError: function() {},\n        onSuccess: function() {},\n        onFinally: function() {},\n});\n```\n\n# Processing Translations\n\nThe Answers SDK provides functionality to perform translation interpolation, pluralization, or both.\n\n## Interpolation \n\nInterpolation allows the use of dynamic values in translations. Interpolation parameters are defined \ninside double brackets, and they must also be defined in an object in the second parameter.\n\nThe following example will return 'Bonjour Howard' provided the variable `myName` equals 'Howard':\n```js\nANSWERS.pr","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyext%2Fanswers-search-ui","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyext%2Fanswers-search-ui","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyext%2Fanswers-search-ui/lists"}