npm package: @searchstax-inc/searchstudio-ux-react
Description: Library to build Site Search page
Latest version: 4.1.72

# sitesearch-ux-react

Library to build Site Search page

## Installation
npm install following package
`npm install --save @searchstax-inc/searchstudio-ux-react`


## Usage

Add the following code to <head>:

```
<script type="text/javascript">
      var _msq = _msq || []; //declare object
      var analyticsBaseUrl = '<https://analytics-us-east.searchstax.co>';
      (function () {
        var ms = document.createElement('script');
        ms.type = 'text/javascript';
        ms.src = '<https://static.searchstax.co/studio-js/v3/js/studio-analytics.js>';
        var s = document.getElementsByTagName('script')[0];
        s.parentNode.insertBefore(ms, s);
      })();
    </script>
```

## Initialization
sampleConfig object needs to be of type: `ISearchstaxConfig`
```
const sampleConfig = {
  language: 'en',
  searchURL: '',
  suggesterURL: '',
  trackApiKey: '',
  searchAuth: '',
  authType: 'basic',
  router: {
    enabled: true,
    routeName: 'searchstax',
    title: (result) => `Search results for: ${result.query}`,
    ignoredKeys: []
  },
  hooks: {
    beforeSearch: (props) => {
// modify props
      return props;
    },
    afterSearch: (results) => {
// modify results
      return results;
    }
  }
};

<SearchstaxWrapper
  language={sampleConfig.language}
  searchURL={sampleConfig.searchURL}
  suggesterURL={sampleConfig.suggesterURL}
  trackApiKey={sampleConfig.trackApiKey}
  searchAuth={sampleConfig.searchAuth}
  authType={sampleConfig.authType}
  router={sampleConfig.router}
  beforeSearch={sampleConfig.hooks.beforeSearch}
  afterSearch={sampleConfig.hooks.afterSearch}
>
</SearchstaxWrapper>


```

## Initial layout
Add any other Site Search components as needed:
```
<SearchstaxWrapper>

  <SearchstaxInputWidget />

  <SearchstaxResultsWidget />

  {/* Other components */}

</SearchstaxWrapper>
```

### widgets
Following widgets are available:

[Answer Widget](#answer-widget)

[Input Widget](#input-widget)

[Location Widget](#location-widget)

[Result Widget](#result-widget)

[Facets Widget](#facets-widget)

[Pagination Widget](#pagination-widget)

[SearchFeedback Widget](#searchfeedback-widget)

[RelatedSearches Widget](#relatedsearches-widget)

[ExternalPromotions Widget](#externalpromotions-widget)

[sorting Widget](#sorting-widget)

### Answer Widget ###
SearchStax Site Search solution offers React and Next.js widgets to assist in building your custom search page.

The SearchstaxAnswerWidget component provides a React and Next.js AI answer widget for your searches.

**Usage**

```
<SearchstaxAnswerWidget
              showMoreAfterWordCount={100}
              feedbackwidget={feedbackConfig}
            ></SearchstaxAnswerWidget>
```

**Props**

- showMoreAfterWordCount - number(default 100) determining after how many words UI will show “Show More” view.
- feedbackWidget – an optional object that configures thumbs-up and thumbs-down feedback functionality.
- searchAnswerTemplate - template override for answers widget

Example of feedbackWidget config:
```
const feedbackConfig = {
    renderFeedbackWidget: true,
    emailOverride: searchstaxEmailOverride,
    thumbsUpValue: 10,
    thumbsDownValue: 0
  }
```


**searchAnswerTemplate**

The templates prop allows customizing the answer UI.

It receives the following props:

- shouldShowAnswer – boolean
- answerErrorMessage – string
- fullAnswerFormatted – string
- showMoreButtonVisible – boolean
- answerLoading – boolean

**Example**

```
function answerTemplate(
  answerData: null | ISearchstaxAnswerData,
  showMore: (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void
) {
  return (
    <>
      {answerData && (
        <div className="searchstax-answer-wrap">
        <div className="searchstax-answer-icon"></div>
        <div>
          <div
            className={
              "searchstax-answer-container " +
              (answerData.showMoreButtonVisible === true ? "searchstax-answer-show-more" : "")
            }
          >
            <div className="searchstax-answer-title">Smart Answers</div>
              {answerData.shouldShowAnswerError && (
                <div className="searchstax-answer-error" dangerouslySetInnerHTML={{__html:answerData.answerErrorMessage}}></div>
              )}
              <div className="searchstax-answer-description" dangerouslySetInnerHTML={{__html:answerData.fullAnswerFormatted}}>
              </div>
                {answerData.answerLoading && (
                  <div className="searchstax-answer-loading"></div>
                )}
          </div>

          {answerData.showMoreButtonVisible === true && (
            <div className="searchstax-answer-load-more-button-container">
              <button
                className="searchstax-answer-load-more-button"
                onClick={(e) => {
                  showMore(e);
                }}
              >
                Show More
              </button>
            </div>
          )}
        </div>
        <div className="searchstax-answer-footer">
            <div id="feedbackWidgetContainer"></div>
            <div className="searchstax-lightweight-widget-separator-inline"></div>
            <p className="searchstax-disclaimer">Generative AI is Experimental</p>
        </div>
        </div>
      )}
    </>
  );
}
<SearchstaxAnswerWidget
              searchAnswerTemplate={answerTemplate}
              showMoreAfterWordCount={100}
            ></SearchstaxAnswerWidget>
```

### Input Widget ###

SearchStax Site Search solution provides React and Next.js widgets to help you build your custom search page.

The SearchstaxInputWidget component provides a search input with autosuggest/autocomplete functionality.

**Usage**
```
<SearchstaxInputWidget
            suggestAfterMinChars={3}
            afterAutosuggest={afterAutosuggest}
            beforeAutosuggest={beforeAutosuggest}
          ></SearchstaxInputWidget>
```

**Props**

- suggestAfterMinChars - default 3. Number of characters needed for autosuggest to start triggering
- beforeAutosuggest - callback function that gets called before firing autosuggest. autosuggestProps are being passed as a property and can be modified, if passed along further search will execute with modified properties, if null is returned then event gets canceled and search never fires.
- afterAutosuggest - callback function that gets called after autosuggest has values but before rendering. It needs to return same type of data but it can be modified.
- inputTemplate - template override. look at examples below


**inputWidgetTemplate**

The inputTemplate prop allows customizing the input UI.

It receives the following props:

- locationEnabled – boolean

**example**
```
const config = {
  appId: "APP_ID",
  relatedSearchesAPIKey: "KEY"
}

const locationWidgetConfig = {
    locationDecode: (term: string): Promise<ISearchstaxLocation> => {
      return new Promise((resolve) => {
        // make a request to google geocoding API to retrieve lat, lon and address

        const geocodingAPIKey = "GEOCODING_API_KEY";
        const geocodingURL = `https://maps.googleapis.com/maps/api/geocode/json?address=${encodeURIComponent(
          term
        )}&key=${geocodingAPIKey}`;
        fetch(geocodingURL)
          .then((response) => response.json())
          .then((data) => {
            if (data.status === "OK" && data.results.length > 0) {
              const result = data.results[0];
              const location = {
                lat: result.geometry.location.lat,
                lon: result.geometry.location.lng,
                address: result.formatted_address,
              };
              resolve(location);
            } else {
              resolve({
                address: undefined,
                lat: undefined,
                lon: undefined,
                error: true,
              });
            }
          })
          .catch(() => {
            resolve({
              address: undefined,
              lat: undefined,
              lon: undefined,
              error: true,
            });
          });
      });
    },
    locationDecodeCoordinatesToAddress: (lat: string, lon: string): Promise<ISearchstaxLocation> => {
      return new Promise((resolve) => {
        fetch(
          `https://geocoding-staging.searchstax.co/reverse?location=${lat},${lon}&components=country:US&app_id=${config.appId}`,
          {
            method: "GET",
            headers: {
              Authorization: `Token ${config.relatedSearchesAPIKey}`,
            },
          }
        )
          .then((response) => response.json())
          .then((data) => {
            if (data.status === "OK" && data.results.length > 0) {
              const result = data.results[0];
              resolve({
                address: result.formatted_address,
                lat: lat,
                lon: lon,
                error: false,
              });
            } else {
              resolve({
                address: undefined,
                lat: lat,
                lon: lon,
                error: true,
              });
            }
          })
          .catch(() => {
            resolve({
              address: undefined,
              lat: lat,
              lon: lon,
              error: true,
            });
          });
      });
    },
    locationSearchEnabled: false,
    locationValuesOverride: {
      locationDistanceEnabled: true,
      filterValues: ["any", "1000"],
      filterUnit: "miles",
      locationFilterDefaultValue: "any"
    },
  }
function LocationTemplate(
    locationData: null | ISearchstaxLocationRenderData,
    locationChange: (value: string) => void,
    locationBlur: (value: string) => void,
    radiusChange: (value: string | number) => void,
    getCurrentLocation: () => void,
    inputValue?: string | null,
    selectValue?: string | number | undefined,
    locationError?: boolean
  ): React.ReactElement {
    return (
     <>
        {locationData && (
          <div
            className="searchstax-location-input-container"
            data-test-id="searchstax-location-input-container"
          >
            <div className="searchstax-location-input-wrapper">
              <span className="searchstax-location-input-label">NEAR</span>
              <div className="searchstax-location-input-wrapper-inner">
                <input
                  type="text"
                  id="searchstax-location-input"
                  className={"searchstax-location-input" + (locationError ? " searchstax-input-location-error" : "")}
                  placeholder="Zip, Postal Code or City..."
                  aria-label="Search Location Input"
                  data-test-id="searchstax-location-input"
                  value={inputValue ?? ""}
                  onChange={(e) => locationChange(e.target.value)}
                  onBlur={(e) => locationBlur(e.target.value)}
                />
                <button onClick={getCurrentLocation} className="searchstax-get-current-location-button">Use my current location</button>
              </div>
              {locationData.shouldShowLocationDistanceDropdown && (
                <span className="searchstax-location-input-label">WITHIN</span>
              )}
              {locationData.shouldShowLocationDistanceDropdown && (
                <select
                  id="searchstax-location-radius-select"
                  className="searchstax-location-radius-select"
                  aria-label="Search Location Radius Select"
                  data-test-id="searchstax-location-radius-select"
                  onChange={(e) => radiusChange(e.target.value)}
                  value={selectValue}
                >
                  {locationData.locationSearchDistanceValues.map(
                    ({ value, label }) => (
                      <option value={value} key={value}>
                        {label}
                      </option>
                    )
                  )}
                </select>
              )}
            </div>
          </div>
        )}
    </>)
  }
function InputTemplate(
  suggestions: ISearchstaxSuggestion[],
  onMouseLeave: () => void,
  onMouseOver: (suggestion: ISearchstaxSuggestion) => void,
  onMouseClick: () => void
): React.ReactElement {
  return (
    <>
      <div className="searchstax-search-input-wrapper">
        <input
          type="text"
          id="searchstax-search-input"
          className="searchstax-search-input"
          placeholder="SEARCH FOR..."
          aria-label="search"
        />
        <div
          className={`searchstax-autosuggest-container ${
            suggestions.length === 0 ? "hidden" : ""
          }`}
          onMouseLeave={onMouseLeave}
        >
          {suggestions.map(function (suggestion) {
            return (
              <div
                className="searchstax-autosuggest-item"
                key={suggestion.term}
              >
                <div
                  className="searchstax-autosuggest-item-term-container"
                  tabIndex={0}
                  dangerouslySetInnerHTML={{ __html: suggestion.term }}
                  onMouseOver={() => {
                    onMouseOver(suggestion);
                  }}
                  onClick={() => {
                    onMouseClick();
                  }}
                ></div>
              </div>
            );
          })}
        </div>
      </div>
      <SearchstaxLocationWidget
        searchLocationTemplate={LocationTemplate}
        hooks={{
          locationDecode: locationWidgetConfig.locationDecode,
          locationDecodeCoordinatesToAddress:
            locationWidgetConfig.locationDecodeCoordinatesToAddress,
        }}
        locationSearchEnabled={locationWidgetConfig.locationSearchEnabled}
        locationValuesOverride={locationWidgetConfig.locationValuesOverride}
      />
      <button
        className="searchstax-spinner-icon"
        id="searchstax-search-input-action-button"
        aria-label="search"
      ></button>
    </>
  );
}

<SearchstaxInputWidget
            afterAutosuggest={afterAutosuggest}
            beforeAutosuggest={beforeAutosuggest}
            inputTemplate={InputTemplate}
          ></SearchstaxInputWidget>
```
### Location Widget ###

SearchStax Site Search solution offers a React search-location widget to assist with your custom search page.

The SearchstaxLocationWidget provides a location search input with location-based search functionality.

**Usage**

```
const config = {
  appId: "APP_ID",
  relatedSearchesAPIKey: "KEY"
}

const locationWidgetConfig = {
    locationDecode: (term: string): Promise<ISearchstaxLocation> => {
      return new Promise((resolve) => {
        // make a request to google geocoding API to retrieve lat, lon and address

        const geocodingAPIKey = "GEOCODING_API_KEY";
        const geocodingURL = `https://maps.googleapis.com/maps/api/geocode/json?address=${encodeURIComponent(
          term
        )}&key=${geocodingAPIKey}`;
        fetch(geocodingURL)
          .then((response) => response.json())
          .then((data) => {
            if (data.status === "OK" && data.results.length > 0) {
              const result = data.results[0];
              const location = {
                lat: result.geometry.location.lat,
                lon: result.geometry.location.lng,
                address: result.formatted_address,
              };
              resolve(location);
            } else {
              resolve({
                address: undefined,
                lat: undefined,
                lon: undefined,
                error: true,
              });
            }
          })
          .catch(() => {
            resolve({
              address: undefined,
              lat: undefined,
              lon: undefined,
              error: true,
            });
          });
      });
    },
    locationDecodeCoordinatesToAddress: (lat: string, lon: string): Promise<ISearchstaxLocation> => {
      return new Promise((resolve) => {
        fetch(
          `https://geocoding-staging.searchstax.co/reverse?location=${lat},${lon}&components=country:US&app_id=${config.appId}`,
          {
            method: "GET",
            headers: {
              Authorization: `Token ${config.relatedSearchesAPIKey}`,
            },
          }
        )
          .then((response) => response.json())
          .then((data) => {
            if (data.status === "OK" && data.results.length > 0) {
              const result = data.results[0];
              resolve({
                address: result.formatted_address,
                lat: lat,
                lon: lon,
                error: false,
              });
            } else {
              resolve({
                address: undefined,
                lat: lat,
                lon: lon,
                error: true,
              });
            }
          })
          .catch(() => {
            resolve({
              address: undefined,
              lat: lat,
              lon: lon,
              error: true,
            });
          });
      });
    },
    locationSearchEnabled: false,
    locationValuesOverride: {
      locationDistanceEnabled: true,
      filterValues: ["any", "1000"],
      filterUnit: "miles",
      locationFilterDefaultValue: "any"
    },
  }
<SearchstaxLocationWidget hooks={ {locationDecode: locationDecodeFunction, locationDecodeCoordinatesToAddress: locationDecodeCoordinatesToAddress} } />
```

**Props**

- locationDecode - callback function to override location decoding
- locationDecodeCoordinatesToAddress - callback function to override location decoding
- searchLocationTemplate - template override for location widget

**Template Override**

The searchLocationTemplate prop allows customizing the location input UI.

It receives the following props:

- locationSearchDistanceValues – location distance values
- shouldShowLocationDistanceDropdown – boolean determining if distance dropdown should be shown


**Example**

```
const config = {
  appId: "APP_ID",
  relatedSearchesAPIKey: "KEY"
}

const locationWidgetConfig = {
    locationDecode: (term: string): Promise<ISearchstaxLocation> => {
      return new Promise((resolve) => {
        // make a request to google geocoding API to retrieve lat, lon and address

        const geocodingAPIKey = "GEOCODING_API_KEY";
        const geocodingURL = `https://maps.googleapis.com/maps/api/geocode/json?address=${encodeURIComponent(
          term
        )}&key=${geocodingAPIKey}`;
        fetch(geocodingURL)
          .then((response) => response.json())
          .then((data) => {
            if (data.status === "OK" && data.results.length > 0) {
              const result = data.results[0];
              const location = {
                lat: result.geometry.location.lat,
                lon: result.geometry.location.lng,
                address: result.formatted_address,
              };
              resolve(location);
            } else {
              resolve({
                address: undefined,
                lat: undefined,
                lon: undefined,
                error: true,
              });
            }
          })
          .catch(() => {
            resolve({
              address: undefined,
              lat: undefined,
              lon: undefined,
              error: true,
            });
          });
      });
    },
    locationDecodeCoordinatesToAddress: (lat: string, lon: string): Promise<ISearchstaxLocation> => {
      return new Promise((resolve) => {
        fetch(
          `https://geocoding-staging.searchstax.co/reverse?location=${lat},${lon}&components=country:US&app_id=${config.appId}`,
          {
            method: "GET",
            headers: {
              Authorization: `Token ${config.relatedSearchesAPIKey}`,
            },
          }
        )
          .then((response) => response.json())
          .then((data) => {
            if (data.status === "OK" && data.results.length > 0) {
              const result = data.results[0];
              resolve({
                address: result.formatted_address,
                lat: lat,
                lon: lon,
                error: false,
              });
            } else {
              resolve({
                address: undefined,
                lat: lat,
                lon: lon,
                error: true,
              });
            }
          })
          .catch(() => {
            resolve({
              address: undefined,
              lat: lat,
              lon: lon,
              error: true,
            });
          });
      });
    },
    locationSearchEnabled: false,
    locationValuesOverride: {
      locationDistanceEnabled: true,
      filterValues: ["any", "1000"],
      filterUnit: "miles",
      locationFilterDefaultValue: "any"
    },
  }
function LocationTemplate(
    locationData: null | ISearchstaxLocationRenderData,
    locationChange: (value: string) => void,
    locationBlur: (value: string) => void,
    radiusChange: (value: string | number) => void,
    getCurrentLocation: () => void,
    inputValue?: string | null,
    selectValue?: string | number | undefined,
    locationError?: boolean
  ): React.ReactElement {
    return (
     <>
        {locationData && (
          <div
            className="searchstax-location-input-container"
            data-test-id="searchstax-location-input-container"
          >
            <div className="searchstax-location-input-wrapper">
              <span className="searchstax-location-input-label">NEAR</span>
              <div className="searchstax-location-input-wrapper-inner">
                <input
                  type="text"
                  id="searchstax-location-input"
                  className={"searchstax-location-input" + (locationError ? " searchstax-input-location-error" : "")}
                  placeholder="Zip, Postal Code or City..."
                  aria-label="Search Location Input"
                  data-test-id="searchstax-location-input"
                  value={inputValue ?? ""}
                  onChange={(e) => locationChange(e.target.value)}
                  onBlur={(e) => locationBlur(e.target.value)}
                />
                <button onClick={getCurrentLocation} className="searchstax-get-current-location-button">Use my current location</button>
              </div>
              {locationData.shouldShowLocationDistanceDropdown && (
                <span className="searchstax-location-input-label">WITHIN</span>
              )}
              {locationData.shouldShowLocationDistanceDropdown && (
                <select
                  id="searchstax-location-radius-select"
                  className="searchstax-location-radius-select"
                  aria-label="Search Location Radius Select"
                  data-test-id="searchstax-location-radius-select"
                  onChange={(e) => radiusChange(e.target.value)}
                  value={selectValue}
                >
                  {locationData.locationSearchDistanceValues.map(
                    ({ value, label }) => (
                      <option value={value} key={value}>
                        {label}
                      </option>
                    )
                  )}
                </select>
              )}
            </div>
          </div>
        )}
    </>)
  }
<SearchstaxLocationWidget searchLocationTemplate={LocationTemplate} hooks={ {locationDecode:locationDecode, locationDecodeCoordinatesToAddress: locationDecodeCoordinatesToAddress} } />
```

### Result Widget ###

The SearchStax Site Search solution provides a React and Next.js results widget to support your custom search page.

The SearchstaxResultsWidget displays the search results.

**Usage**

```
<SearchstaxResultWidget
                afterLinkClick={afterLinkClick}
                renderMethod={'pagination'}
                resultsPerPage={10}
              ></SearchstaxResultWidget>
```

**Props**

- renderMethod – either “pagination” or “infiniteScroll”.
- resultsPerPage – number of results on a page.
- afterLinkClick – Callback function invoked when a result link is clicked. Allows modifying the result object.
- resultsTemplate - template override for result view
- noResultTemplate - template override for no results view


**Result Template Override**

The resultsTemplate prop allows customizing the result UI.

It receives no props:
- custom?: any - custom properties that may be added through aftersearchHook
- ribbon: string | null
- paths: string | null;
- url: string | null;
- title: string | null;
- titleTracking: string | null;
- promoted: boolean | null;
- thumbnail: string | null;
- date: string | null;
- snippet: string | null;
- description: string | null;
- uniqueId: string;
- position: number;
- distance: number | null;
- unit: string | null;
- unmappedFields: {
   key: string;
   value: string | string[] | boolean;
   isImage?: boolean;
 }[] - fields that were not mapped.
- allFields: { key: string; value: string | string[] | boolean }[] - all fields


**No Results Template Override**

The noResultTemplate prop allows customizing the result UI.

It receives following props:

- spellingSuggestion - suggestion of corrected spelling
- searchExecuted - boolean if search was executed
- searchTerm - term that was searched

**Example of default render method**
```

```

**Example of infinite scroll and pagination render methods**
```
function noResultTemplate(
  searchTerm: string,
  metaData: ISearchstaxSearchMetadata | null,
  executeSearch: (searchTerm: string) => void
): React.ReactElement {
  return (
    <div>
      <div className="searchstax-no-results">
        {" "}
        Showing <strong>no results</strong> for <strong>"{searchTerm}"</strong>
        <br />
        {metaData?.spellingSuggestion && (
          <span>
            &nbsp;Did you mean{" "}
            <a
              href="#"
              aria-label={`Did you mean ${metaData?.spellingSuggestion}`}
              className="searchstax-suggestion-term"
              onClick={(e) => {
                e.preventDefault();
                executeSearch(metaData?.spellingSuggestion);
              }}
            >
              {metaData?.spellingSuggestion}
            </a>
            ?
          </span>
        )}
      </div>
      <ul>
        <li>
          {" "}
          Try searching for search related terms or topics. We offer a wide
          variety of content to help you get the information you need.{" "}
        </li>
      </ul>
    </div>
  );
}

function resultsTemplate(
  searchResults: ISearchstaxParsedResult[],
  resultClicked: (
    results: ISearchstaxParsedResult,
    event: any
  ) => void
): React.ReactElement {
  return (
    <>
      {searchResults && searchResults.length && (
        <div className="searchstax-search-results" aria-live="polite">
          {searchResults !== null &&
            searchResults.map(function (searchResult) {
              return (
                <a
                  href={searchResult.url ?? ""}
                  onClick={(event) => {
                    resultClicked(searchResult, event);
                  }}
                  onKeyDown={(e) => {
                    if (e.key === "Enter" || e.key === " ") {
                      resultClicked(searchResult, e);
                    }
                  }}
                  data-searchstax-unique-result-id={searchResult.uniqueId}
                  key={searchResult.uniqueId}
                  aria-labelledby={`title-${searchResult.uniqueId}`}
                  className="searchstax-result-item-link searchstax-result-item-link-wrapping"
                  tabIndex={0}
                >
                  <div
                    className={`searchstax-search-result ${
                      searchResult.thumbnail ? "has-thumbnail" : ""
                    }`}
                    key={searchResult.uniqueId}
                  >
                    {searchResult.promoted && (
                      <div className="searchstax-search-result-promoted"></div>
                    )}

                    {searchResult.ribbon && (
                      <div
                        className="searchstax-search-result-ribbon"
                        dangerouslySetInnerHTML={{
                          __html: searchResult.ribbon,
                        }}
                      ></div>
                    )}

                    {searchResult.thumbnail && (
                      <img
                        alt=""
                        src={searchResult.thumbnail}
                        className="searchstax-thumbnail"
                      />
                    )}

                    <div className="searchstax-search-result-title-container">
                      <span
                        className="searchstax-search-result-title"
                        id={`title-${searchResult.uniqueId}`}
                        dangerouslySetInnerHTML={{
                          __html: searchResult.title ?? "",
                        }}
                      ></span>
                    </div>

                    {searchResult.paths && (
                      <p
                        className="searchstax-search-result-common"
                        tabIndex={0}
                        dangerouslySetInnerHTML={{ __html: searchResult.paths }}
                      ></p>
                    )}

                    {searchResult.description && (
                      <p
                        className="searchstax-search-result-description searchstax-search-result-common"
                        tabIndex={0}
                        dangerouslySetInnerHTML={{
                          __html: searchResult.description,
                        }}
                      ></p>
                    )}

                    {searchResult.unmappedFields.map(function (
                      unmappedField: any
                    ) {
                      return (
                        <div key={unmappedField.key}>
                          {unmappedField.isImage &&
                            typeof unmappedField.value === "string" && (
                              <div className="searchstax-search-result-image-container">
                                <img
                                  alt=""
                                  src={unmappedField.value}
                                  className="searchstax-result-image"
                                />
                              </div>
                            )}

                          {!unmappedField.isImage && (
                            <div>
                              <p
                                tabIndex={0}
                                className="searchstax-search-result-common"
                                dangerouslySetInnerHTML={{
                                  __html: unmappedField.value,
                                }}
                              ></p>
                            </div>
                          )}
                        </div>
                      );
                    })}
                  </div>
                </a>
              );
            })}
        </div>
      )}
    </>
  );
}
<SearchstaxResultWidget
                afterLinkClick={afterLinkClick}
                noResultTemplate={noResultTemplate}
                resultsTemplate={resultsTemplate}
                renderMethod={'pagination'}
              ></SearchstaxResultWidget>
  // Infinite scroll

<SearchstaxResultWidget
                afterLinkClick={afterLinkClick}
                noResultTemplate={noResultTemplate}
                resultsTemplate={resultsTemplate}
                renderMethod={'infiniteScroll'}
              ></SearchstaxResultWidget>

```

### Pagination Widget ###

The SearchStax Site Search solution offers a pagination widget for React and Next.js search pages.

The SearchstaxPaginationWidget displays pagination controls for search results.

**Usage**

```
<SearchstaxPaginationWidget></SearchstaxPaginationWidget>
```

**Props**
- paginationTemplate - template override for pagination widget

**Main Template Override**

Main template for the pagination controls.

It receives following props:

- nextPageLink - link of next page;
- previousPageLink - link of previous page;


**Infinite Scroll Template Override**

Main template for the pagination controls in infinite scroll mode.

It receives following props:
- isLastPage - boolean, true if its last page
- results - results.length can be used if there are results

**Example**

```
function paginationTemplate(
    paginationData: IPaginationData | null,
    nextPage: (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => void,
    previousPage: (
      event: React.MouseEvent<HTMLAnchorElement, MouseEvent>
    ) => void
  ) {
    return (
      <>
        {paginationData && paginationData?.totalResults !== 0 && (
          <div className="searchstax-pagination-container">
            <div className="searchstax-pagination-content">
              <a
                className={`searchstax-pagination-previous ${paginationData.isFirstPage ? "disabled" : ""}`}
                tabIndex={0}
                style={
                  paginationData?.isFirstPage ? { pointerEvents: "none" } : {}
                }
                onClick={(e) => {
                  previousPage(e);
                }}
                onKeyDown={(e) => {
                  if(e.key === 'Enter' || e.key === ' ') {
                    previousPage(e as any);
                  }
                }}
                id="searchstax-pagination-previous"
              >
                {" "}
                &lt; Previous{" "}
              </a>
              <div className="searchstax-pagination-details">
                {" "}
                {paginationData?.startResultIndex} -{" "}
                {paginationData?.endResultIndex} of{" "}
                {paginationData?.totalResults}
              </div>
              <a
                className={`searchstax-pagination-next ${paginationData.isLastPage ? "disabled" : ""}`}
                tabIndex={0}
                style={
                  paginationData?.isLastPage ? { pointerEvents: "none" } : {}
                }
                onClick={(e) => {
                  nextPage(e);
                }}
                onKeyDown={(e) => {
                  if(e.key === 'Enter' || e.key === ' ') {
                    nextPage(e as any);
                  }
                }}
                id="searchstax-pagination-next"
              >
                Next &gt;
              </a>
            </div>
          </div>
        )}
      </>
    );
  }

  function infiniteScrollTemplate(
    paginationData: IPaginationData | null,
    nextPage: (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => void
  ) {
    return (
      <>
        {paginationData &&
          paginationData.isInfiniteScroll &&
          paginationData?.totalResults !== 0 &&
          !paginationData?.isLastPage && (
            <div className="searchstax-pagination-container">
              <a
                className="searchstax-pagination-load-more"
                tabIndex={0}
                onClick={(e) => {
                  nextPage(e);
                }}
                onKeyDown={(e) => {
                  if(e.key === 'Enter' || e.key === ' ') {
                    nextPage(e as any);
                  }
                }}
              >
                Show More &gt;
              </a>
            </div>
          )}
      </>
    );
  }
<SearchstaxPaginationWidget paginationTemplate={paginationTemplate}></SearchstaxPaginationWidget>
// example of pagination widget for infinite scroll
<SearchstaxPaginationWidget infiniteScrollTemplate={infiniteScrollTemplate}></SearchstaxPaginationWidget>
```

### Facets Widget ###

The SearchStax Site Search solution offers a SearchstaxFacetsWidget component for React and Next.js. This widget displays the search facets.

**Facet Selection and Order**

Facet lists are configured and ordered on the Site Search [Faceting Tab](https://www.searchstax.com/docs/searchstudio/faceting-tab/).

**Usage**

```
<SearchstaxFacetsWidget
                facetingType="and"
                itemsPerPageDesktop={2}
                itemsPerPageMobile={3}
                specificFacets={undefined}
              ></SearchstaxFacetsWidget>
```

**Props**

- facetingType: "and" | "or" | "showUnavailable" | "tabs"; // type that determines how facets will behave
- specificFacets?: string[]; // optional array of facet names that if provided will only render those facets
- itemsPerPageDesktop: number; // default expanded facets for desktop
- itemsPerPageMobile: number; // default expanded facets for mobile
- facetsTemplateDesktop - template override for desktop view
- facetsTemplateMobile - template override for mobile view
- beforeFacetsRender `(facets: IFacetData[]) => IFacetData[]` — Called with the current facets array before the widget renders. Return the same or a modified array to filter, reorder, or transform facets (e.g., hide certain facets or change their order).


**Main Template Desktop Override**

Main wrapper template for desktop facets display.

It receives following props from [IFacetsTemplateData](https://www.searchstax.com/docs/searchstudio/interfaces/#h-facets-interfaces)


**Main Template Mobile Override**

Main wrapper template for mobile facets display.

It receives following props from [IFacetsTemplateData](https://www.searchstax.com/docs/searchstudio/interfaces/#h-facets-interfaces)


**Example**
```
 function facetsTemplateDesktop(
  facetsTemplateDataDesktop: IFacetsTemplateData | null,
  facetContainers: {
    [key: string]: React.LegacyRef<HTMLDivElement> | undefined;
  },
  isNotDeactivated: (name: string) => boolean,
  toggleFacetGroup: (name: string) => void,
  selectFacet: (
    index: string,
    event: React.MouseEvent<HTMLDivElement, MouseEvent>,
    data: IFacetValueData,
    isInput: boolean
  ) => void,
  isChecked: (facetValue: IFacetValueData) => boolean | undefined,
  showMoreLessDesktop: (
    e: React.MouseEvent<HTMLDivElement, MouseEvent>,
    data: IFacetData
  ) => void
) {
  return (
    <div className="searchstax-facets-container-desktop">
      {facetsTemplateDataDesktop?.facets.map((facet) => {
        return (
          <div
            className={`searchstax-facet-container ${
              isNotDeactivated(facet.name) ? "active" : ""
            }`}
            key={facet.name + "desktop"}
          >
            <div>
              <div
                className="searchstax-facet-title-container"
                onClick={() => {
                  toggleFacetGroup(facet.name);
                }}
              >
                <div className="searchstax-facet-title">
                  {" "}
                  {facet.label}
                </div>
                <div className="searchstax-facet-title-arrow active"></div>
              </div>
              <div className="searchstax-facet-values-container" aria-live="polite">
                {facet.values.map(
                  //@ts-ignore
                  (facetValue: IFacetValueData, key) => {
                    facetContainers[key + facet.name] = createRef();
                    return (
                      <div
                        key={facetValue.value + facetValue.parentName}
                        className={`searchstax-facet-value-container ${
                          facetValue.disabled
                            ? "searchstax-facet-value-disabled"
                            : ""
                        }`}
                        ref={facetContainers[key + facet.name]}
                      >
                        <div
                          className={
                            "searchstax-facet-input" +
                            " desktop-" +
                            key +
                            facet.name
                          }
                        >
                          <input
                            type="checkbox"
                            className="searchstax-facet-input-checkbox"
                            checked={isChecked(facetValue)}
                            readOnly={true}
                            aria-label={facetValue.value + ' ' + facetValue.count}
                            disabled={facetValue.disabled}
                            onClick={(e) => {
                              selectFacet(
                                key + facet.name,
                                e,
                                facetValue,
                                true
                              );
                            }}
                          />
                        </div>
                        <div
                          className="searchstax-facet-value-label"
                          onClick={(e) => {
                            selectFacet(key + facet.name, e, facetValue, false);
                          }}
                        >
                          {facetValue.value}
                        </div>
                        <div
                          className="searchstax-facet-value-count"
                          onClick={(e) => {
                            selectFacet(key + facet.name, e, facetValue, false);
                          }}
                        >
                          ({facetValue.count})
                        </div>
                      </div>
                    );
                  }
                )}

                {facet.hasMoreFacets && (
                  <div className="searchstax-facet-show-more-container">
                    <div
                      className="searchstax-facet-show-more-container"
                      onClick={(e) => {
                        showMoreLessDesktop(e, facet);
                      }}
                      onKeyDown={(e) => {
                        if(e.key === 'Enter' || e.key === ' ') {
                          showMoreLessDesktop(e as any, facet);
                        }
                      }}
                      tabIndex={0}
                    >
                      {facet.showingAllFacets && (
                        <div className="searchstax-facet-show-less-button searchstax-facet-show-button">
                          less
                        </div>
                      )}
                      {!facet.showingAllFacets && (
                        <div className="searchstax-facet-show-more-button  searchstax-facet-show-button">
                          more
                        </div>
                      )}
                    </div>
                  </div>
                )}
              </div>
            </div>
          </div>
        );
      })}
    </div>
  );
}

function facetsTemplateMobile(
  facetsTemplateDataMobile: IFacetsTemplateData | null,
  selectedFacetsCheckboxes: IFacetValue[],
  facetContainers: {
    [key: string]: React.LegacyRef<HTMLDivElement> | undefined;
  },
  isNotDeactivated: (name: string) => boolean,
  toggleFacetGroup: (name: string) => void,
  selectFacet: (
    index: string,
    event: React.MouseEvent<HTMLDivElement, MouseEvent>,
    data: IFacetValueData,
    isInput: boolean,
    isMobile?: boolean
  ) => void,
  isChecked: (facetValue: IFacetValueData) => boolean | undefined,
  unselectFacet: (facet: IFacetValue) => void,
  showMoreLessMobile: (
    e: React.MouseEvent<HTMLDivElement, MouseEvent>,
    data: IFacetData
  ) => void,
  openOverlay: () => void,
  closeOverlay: () => void,
  unselectAll: () => void
) {
  return facetsTemplateDataMobile ? (
    <div className="searchstax-facets-container-mobile">
      <div className="searchstax-facets-pills-container">
        <div
          className="searchstax-facets-pill searchstax-facets-pill-filter-by"
          onClick={() => {
            openOverlay();
          }}
        >
          <div className="searchstax-facets-pill-label">Filter By</div>
        </div>
        <div className="searchstax-facets-pills-selected">
          {selectedFacetsCheckboxes.map((facet) => {
            return (
              <div
                className="searchstax-facets-pill searchstax-facets-pill-facets"
                key={facet.value}
                onClick={() => {
                  unselectFacet(facet);
                }}
              >
                <div className="searchstax-facets-pill-label">
                  {facet.value} ({facet.count})
                </div>
                <div className="searchstax-facets-pill-icon-close"></div>
              </div>
            );
          })}
          {selectedFacetsCheckboxes.length !== 0 && (
            <div
              className="searchstax-facets-pill searchstax-clear-filters searchstax-facets-pill-clear-all"
              onClick={() => {
                unselectAll();
              }}
            >
              <div className="searchstax-facets-pill-label">Clear Filters</div>
            </div>
          )}
        </div>
        <div
          className={`searchstax-facets-mobile-overlay ${
            //@ts-ignore
            facetsTemplateDataMobile.overlayOpened ? "searchstax-show" : ""
          }`}
        >
          <div className="searchstax-facets-mobile-overlay-header">
            <div className="searchstax-facets-mobile-overlay-header-title">
              Filter By
            </div>
            <div
              className="searchstax-search-close"
              onClick={() => {
                closeOverlay();
              }}
            ></div>
          </div>
          <div className="searchstax-facets-container-mobile">
            {facetsTemplateDataMobile?.facets.map((facet) => {
              return (
                <div
                  key={facet.name + "mobile"}
                  className={`searchstax-facet-container ${
                    isNotDeactivated(facet.name) ? `active` : ``
                  }`}
                >
                  <div>
                    <div
                      className="searchstax-facet-title-container"
                      onClick={() => {
                        toggleFacetGroup(facet.name);
                      }}
                    >
                      <div className="searchstax-facet-title">
                        {" "}
                        {facet.label}{" "}
                      </div>
                      <div className="searchstax-facet-title-arrow active"></div>
                    </div>
                    <div className="searchstax-facet-values-container" aria-live="polite">
                      {facet.values.map(
                        //@ts-ignore
                        (facetValue: IFacetValueData, key) => {
                          facetContainers[key + facet.name] = createRef();

                          return (
                            <div
                              key={facetValue.value + facetValue.parentName}
                              className={`searchstax-facet-value-container ${
                                facetValue.disabled
                                  ? `searchstax-facet-value-disabled`
                                  : ``
                              }`}
                              ref={facetContainers[key + facet.name]}
                            >
                              <div
                                className={
                                  "searchstax-facet-input" +
                                  " mobile-" +
                                  key +
                                  facet.name
                                }
                              >
                                <input
                                  type="checkbox"
                                  className="searchstax-facet-input-checkbox"
                                  checked={isChecked(facetValue)}
                                  readOnly={true}
                                  aria-label={facetValue.value + ' ' + facetValue.count}
                                  disabled={facetValue.disabled}
                                  onClick={(e) => {
                                    selectFacet(
                                      key + facet.name,
                                      e,
                                      facetValue,
                                      true,
                                      true
                                    );
                                  }}
                                />
                              </div>
                              <div
                                className="searchstax-facet-value-label"
                                onClick={(e) => {
                                  selectFacet(
                                    key + facet.name,
                                    e,
                                    facetValue,
                                    false
                                  );
                                }}
                              >
                                {facetValue.value}
                              </div>
                              <div
                                className="searchstax-facet-value-count"
                                onClick={(e) => {
                                  selectFacet(
                                    key + facet.name,
                                    e,
                                    facetValue,
                                    false
                                  );
                                }}
                              >
                                ({facetValue.count})
                              </div>
                            </div>
                          );
                        }
                      )}

                      <div
                        className="searchstax-facet-show-more-container"
                        v-if="facet.hasMoreFacets"
                      >
                        <div
                          className="searchstax-facet-show-more-container"
                          onClick={(e) => {
                            showMoreLessMobile(e, facet);
                          }}
                          onKeyDown={(e) => {
                            if(e.key === 'Enter' || e.key === ' ') {
                              showMoreLessMobile(e as any, facet);
                            }
                          }}
                          tabIndex={0}
                          role="button"
                        >
                          {facet.showingAllFacets && (
                            <div className="searchstax-facet-show-less-button searchstax-facet-show-button">
                              less
                            </div>
                          )}
                          {!facet.showingAllFacets && (
                            <div className="searchstax-facet-show-more-button  searchstax-facet-show-button">
                              more
                            </div>
                          )}
                        </div>
                      </div>
                    </div>
                  </div>
                </div>
              );
            })}
          </div>
          <button
            className="searchstax-facets-mobile-overlay-done"
            onClick={() => {
              closeOverlay();
            }}
          >
            Done
          </button>
        </div>
      </div>
    </div>
  ) : (
    <></>
  );
}
<SearchstaxFacetsWidget
                facetingType="and"
                itemsPerPageDesktop={2}
                itemsPerPageMobile={3}
                specificFacets={undefined}
                facetsTemplateDesktop={facetsTemplateDesktop}
                facetsTemplateMobile={facetsTemplateMobile}
              ></SearchstaxFacetsWidget>
```

### SearchFeedback Widget ###

The SearchStax Site Search solution provides a search feedback widget to support your React and Next.js search pages.

The SearchstaxFeedbackWidget displays search feedback and stats.

**Usage**

```
<SearchstaxOverviewWidget></SearchstaxOverviewWidget>
```

**Props**

- searchOverviewTemplate - template override for search overview

**Main Template Override**

Main template for the search feedback message.

It receives following props:
- searchExecuted - boolean, true if search was executed
- hasResults - boolean, true if search has results
- startResultIndex - number, start of page results
- endResultIndex - number, end of page results
- totalResults - number, total results
- searchTerm - term that was searched
- autoCorrectedQuery - query that search was autocorrected to
- originalQuery - original query

**Example**
```
function searchOverviewTemplate(
    searchFeedbackData: null | ISearchstaxSearchFeedbackData,
    onOriginalQueryClick: (
      event: React.MouseEvent<HTMLAnchorElement, MouseEvent>
    ) => void
  ) {
    return (
      <>
        {searchFeedbackData &&
          searchFeedbackData?.searchExecuted &&
          searchFeedbackData?.totalResults > 0 && (
            <>
              Showing{" "}
              <b>
                {searchFeedbackData.startResultIndex} -{" "}
                {searchFeedbackData.endResultIndex}
              </b>{" "}
              of
              <b> {searchFeedbackData.totalResults}</b> results
              {searchFeedbackData.searchTerm && (
                <span>
                  &nbsp;for "<b>{searchFeedbackData.searchTerm}</b>"{" "}
                </span>
              )}
              <div className="searchstax-feedback-container-suggested">
                {searchFeedbackData.autoCorrectedQuery && (
                  <div>
                    {" "}
                    Search instead for{" "}
                    <a
                      href="#"
                      onClick={(e) => {
                        onOriginalQueryClick(e);
                      }}
                      className="searchstax-feedback-original-query"
                      aria-label={`Search instead for ${searchFeedbackData.originalQuery}`}
                    >
                      {searchFeedbackData.originalQuery}
                    </a>
                  </div>
                )}
              </div>
            </>
          )}
      </>
    );
  }
<SearchstaxOverviewWidget searchOverviewTemplate={searchOverviewTemplate}></SearchstaxOverviewWidget>
```

### RelatedSearches widget ###

The SearchStax Site Search solution offers a related-searches widget for React and Next.js search pages.

The SearchstaxRelatedSearchesWidget displays related searches.

**Usage**
```
  <SearchstaxRelatedSearchesWidget
                relatedSearchesURL={config.relatedSearchesURL}
                relatedSearchesAPIKey={config.relatedSearchesAPIKey}
              ></SearchstaxRelatedSearchesWidget>
```

**Props**

- relatedSearchesURL: // : An endpoint from the Discovery tab of the App Settings > All APls screen.
- relatedSearchesAPIKey?: The Discovery API key from the Discovery tab of the App Settings > All
- searchRelatedSearchesTemplate - template override for related searches

**Main Template Override**

Main template for related searches.

It receives following props:

- hasRelatedSearches - boolean, true if has related searches
- relatedSearches - array of related searches
- related_search - string, related searc
- last - boolean, true if last related search

**Example**

```
 function searchRelatedSearchesTemplate(
    relatedData: null | ISearchstaxRelatedSearchesData,
    executeSearch: (result: ISearchstaxRelatedSearchResult) => void
  ) {
    return (
      <>
        {relatedData &&
          relatedData?.searchExecuted &&
          relatedData?.hasRelatedSearches && (
            <div
              className="searchstax-related-searches-container"
              id="searchstax-related-searches-container"
            >
              {" "}
              Related searches: <span id="searchstax-related-searches"></span>
              {relatedData.relatedSearches && (
                <span className="searchstax-related-search">
                  {relatedData.relatedSearches.map((related) => (
                    <span
                      key={related.related_search}
                      onClick={() => {
                        executeSearch(related);
                      }}
                      onKeyDown={(e) => {
                        if(e.key === 'Enter' || e.key === ' ') {
                          executeSearch(related);
                        }
                      }}
                      tabIndex={0}
                      className="searchstax-related-search searchstax-related-search-item"
                      aria-label={'Related search: ' + related.related_search}
                    >
                      {" "}
                      {related.related_search}
                      {!related.last && <span>,</span>}
                    </span>
                  ))}
                </span>
              )}
            </div>
          )}
      </>
    );
  }
  <SearchstaxRelatedSearchesWidget
                relatedSearchesURL={config.relatedSearchesURL}
                relatedSearchesAPIKey={config.relatedSearchesAPIKey}
                searchRelatedSearchesTemplate={searchRelatedSearchesTemplate}
              ></SearchstaxRelatedSearchesWidget>
```

### ExternalPromotions widget ###

The SearchStax Site Search solution offers an external-promotions widget to assist with your React and Next.js custom search pages.

The SearchstaxExternalPromotionsWidget displays external promotions fetched from the API.

**Usage**

```
<SearchstaxExternalPromotionsWidget></SearchstaxExternalPromotionsWidget>
```

**Props**

- searchExternalPromotionsTemplate - template override for external promotions widget

**Main Template Override**

Main template for external promotions.

It receives following props:

- hasExternalPromotions - boolean, true if has external promotions
- url - url of external promotion
- uniqueId - unique id
- name - name of promotion
- description - description

**Example**
```
function searchExternalPromotionsTemplate(
  externalPromotionsData: null | ISearchstaxExternalPromotionsData,
  trackClick: (
    externalPromotion: IExternalPromotion,
    event: React.MouseEvent<HTMLAnchorElement, MouseEvent>
  ) => void
) {
  return (
    <>
      {externalPromotionsData &&
        externalPromotionsData?.searchExecuted &&
        externalPromotionsData?.hasExternalPromotions &&
        externalPromotionsData.externalPromotions.map((externalPromotion) => (
          <div
            className="searchstax-external-promotion searchstax-search-result"
            key={externalPromotion.id}
          >
            <div className="icon-elevated"></div>
            {externalPromotion.url && (
              <a
                href={externalPromotion.url}
                onClick={(event) => {
                  trackClick(externalPromotion, event);
                }}
                className="searchstax-result-item-link"
              ></a>
            )}
            <div className="searchstax-search-result-title-container">
              <span className="searchstax-search-result-title">
                {externalPromotion.name}
              </span>
            </div>
            {externalPromotion.description && (
              <p className="searchstax-search-result-description searchstax-search-result-common">
                {" "}
                {externalPromotion.description}{" "}
              </p>
            )}
            {externalPromotion.url && (
              <p className="searchstax-search-result-description searchstax-search-result-common">
                {" "}
                {externalPromotion.url}{" "}
              </p>
            )}
          </div>
        ))}
    </>
  );
}
<SearchstaxExternalPromotionsWidget
                searchExternalPromotionsTemplate={searchExternalPromotionsTemplate}
              ></SearchstaxExternalPromotionsWidget>
```


### Sorting Widget ###

The SearchStax Site Search solution offers a sorting widget for your React or Next.js custom search page.

The SearchstaxSortingWidget displays sorting options for search results.

**Usage**

```
<SearchstaxSortingWidget></SearchstaxSortingWidget>
```

**Props**

- searchSortingTemplate - template override for sorting widget

**Main Template Override**

Main template for sorting widget.

It receives following props:

- searchExecuted - boolean, true if search was executed
- hasResultsOrExternalPromotions - boolean, true if there are results or external promotions
- sortOptions - array of sort options, has key/value

**Example**

```
function searchSortingTemplate(
    sortingData: null | ISearchstaxSearchSortingData,
    orderChange: (value: string) => void,
    selectedSorting: string
  ) {
    return (
      <>
        {sortingData &&
          sortingData?.searchExecuted &&
          sortingData.sortOptions.length > 0 &&
          sortingData?.hasResultsOrExternalPromotions && (
            <div className="searchstax-sorting-container">
              <label className="searchstax-sorting-label" htmlFor="searchstax-search-order-select">
                Sort By
              </label>
              <select
                id="searchstax-search-order-select"
                className="searchstax-search-order-select"
                value={selectedSorting}
                onChange={(e) => {
                  orderChange(e.target.value);
                }}
              >
                {sortingData.sortOptions.map(function (sortOption) {
                  return (
                    <option key={sortOption.key} value={sortOption.key}>
                      {sortOption.value}
                    </option>
                  );
                })}
              </select>
            </div>
          )}
      </>
    );
  }
  <SearchstaxSortingWidget searchSortingTemplate={searchSortingTemplate}></SearchstaxSortingWidget>
```


## Template overrides
Templates use relatedsearches templating.

## STYLING

scss styles can be imported from searchstudio-ux-js
```
 @import './../node_modules/@searchstax-inc/searchstudio-ux-js/dist/styles/scss/mainTheme.scss';
```
css can be taken from

```
./../node_modules/@searchstax-inc/searchstudio-ux-js/dist/styles/mainTheme.css
```