npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@searchstax-inc/searchstudio-ux-js

v4.1.47

Published

Library to build Site Search page

Readme

sitesearch-ux-js

Library to build Site Search page

Installation

npm install following package npm install --save @searchstax-inc/searchstudio-ux-js

Usage

After importing Searchstax class a new instance needs to be created:

const searchstax = new Searchstax();

Initialization

Initialization object needs to be of type: ISearchstaxConfig

interface ISearchstaxConfig {
  sessionId?: string; // session id that is used for tracking. if not defined random value will be generated
  language: string; // language code. Example: 'en'
  model?: string; // Site Search model name.
  searchURL: string; // Site Search select endpoint
  suggesterURL: string; //Site Search suggest endpoint
  trackApiKey: string; // Api key used for tracking events
  searchAuth: string; // Authentication value. based on authType it's either a token value or basic auth value
  authType: "token" | "basic"; // Type of authentication
  autoCorrect?: boolean; // if set to true it will autoCorrect misspelled words. Default is false
  router?: IRouterConfig; // optional object containing router settings
  analyticsBaseUrl?: string; // url for analytics calls
  questionURL?: string; // url for AI answer widget
  hooks?: {
    // optional object that provides various hook options
    beforeSearch?: (props: ISearchObject) => ISearchObject | null; // this function gets called before firing search. searchProps 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.
    afterSearch?: (results: ISearchstaxParsedResult[]) => ISearchstaxParsedResult[]; // this function gets called after firing search and before rendering. It needs to return array of results that are either modified or untouched.
  };
}

Initialization example

searchstax.initialize({
    language: "en",
    model: "Main Profile",
    searchURL: "",
    suggesterURL: "",
    trackApiKey: "",
    searchAuth: "",
    sessionId: "yourSessionId",
    authType: "basic",
    questionURL: "",
    router: {
      enabled: true,
      routeName: "searchstax",
      title: (result: ISearchObject) => {
        return "Search results for: " + result.query;
      },
      ignoredKeys: [],
    },
    analyticsBaseUrl: 'https://analytics-us-east.searchstax.com',
    hooks: {
      beforeSearch: function (props: ISearchObject) {
        const propsCopy = { ...props };
        return propsCopy;
      },
      afterSearch: function (results: ISearchstaxParsedResult[]) {
        const copy = [...results];
        return copy;
      },
    }
  });

Initial layout

Our base theme is designed with this layout in mind but it is optional as all widgets have id parameters and can be attached to any element.

<div class="searchstax-page-layout-container">
      <div id="searchstax-input-container"></div>

      <div class="search-details-container">
        <div id="search-feedback-container"></div>
        <div id="search-sorting-container"></div>
      </div>

      <div class="searchstax-page-layout-facet-result-container">
        <div class="searchstax-page-layout-facet-container">
          <div id="searchstax-facets-container"></div>
        </div>

        <div class="searchstax-page-layout-result-container">
          <div id="searchstax-external-promotions-layout-container"></div>
          <div id="searchstax-results-container"></div>
          <div id="searchstax-related-searches-container"></div>
          <div id="searchstax-pagination-container"></div>
        </div>
      </div>
</div>

widgets

Following widgets are available:

Answer Widget

Input Widget

Location Widget

Result Widget

Facets Widget

Pagination Widget

SearchFeedback Widget

RelatedSearches Widget

ExternalPromotions Widget

sorting Widget

advanced data flow subscriptions

Following widgets are available:

Data flow subscriptions

Answer Widget

SearchStax Site Search solution offers Native JS widgets to assist in building your custom search page.

The SearchstaxAnswerWidget component for JS provides an AI answer widget for your searches.

Usage

searchstax.addAnswerWidget("searchstax-answer-container", {
  showMoreAfterWordCount: 100,
  feedbackwidget: feedbackConfig
});

Props

  • showMoreAfterWordCount - number(default 100) determining after how many words UI will show “Read More” view.
  • feedbackWidget – an optional object that configures thumbs-up and thumbs-down feedback functionality.
  • templates - template override. look at examples below

Example of feedbackWidget config:

const feedbackConfig = {
    renderFeedbackWidget: true,
    emailOverride: searchstaxEmailOverride,
    thumbsUpValue: 10,
    thumbsDownValue: 0,
    lightweightTemplateOverride: `
     <div class="searchstax-lightweight-widget-container">
     <div class="searchstax-lightweight-widget-thumbs-up {{#thumbsUpActive}}active{{/thumbsUpActive}}">
     <svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
      <path d="M4.85079 7.59996L7.83141 1C8.4243 1 8.9929 1.23178 9.41213 1.64436C9.83136 2.05694 10.0669 2.61651 10.0669 3.19999V6.1333H14.2845C14.5005 6.13089 14.7145 6.17474 14.9116 6.26179C15.1087 6.34885 15.2842 6.47704 15.426 6.63747C15.5677 6.79791 15.6723 6.98676 15.7326 7.19094C15.7928 7.39513 15.8072 7.60975 15.7748 7.81996L14.7465 14.4199C14.6926 14.7696 14.5121 15.0884 14.2382 15.3175C13.9643 15.5466 13.6156 15.6706 13.2562 15.6666H4.85079M4.85079 7.59996V15.6666M4.85079 7.59996H2.61531C2.22006 7.59996 1.84099 7.75448 1.5615 8.02953C1.28201 8.30458 1.125 8.67763 1.125 9.06661V14.1999C1.125 14.5889 1.28201 14.9619 1.5615 15.237C1.84099 15.512 2.22006 15.6666 2.61531 15.6666H4.85079"  stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
      </svg>
</div>
     <div class="searchstax-lightweight-widget-separator"></div>
     <div class="searchstax-lightweight-widget-thumbs-down {{#thumbsDownActive}}active{{/thumbsDownActive}}">
      <svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
      <path d="M12.1492 9.06801L9.16859 15.668C8.5757 15.668 8.0071 15.4362 7.58787 15.0236C7.16864 14.611 6.93311 14.0515 6.93311 13.468V10.5347H2.71552C2.4995 10.5371 2.28552 10.4932 2.08842 10.4062C1.89132 10.3191 1.71581 10.1909 1.57405 10.0305C1.43229 9.87006 1.32766 9.6812 1.26743 9.47702C1.2072 9.27284 1.19279 9.05822 1.22521 8.84801L2.25353 2.24806C2.30742 1.89833 2.48793 1.57955 2.76179 1.35046C3.03566 1.12136 3.38443 0.997398 3.74384 1.0014H12.1492M12.1492 9.06801V1.0014M12.1492 9.06801H14.3847C14.7799 9.06801 15.159 8.91349 15.4385 8.63844C15.718 8.36339 15.875 7.99034 15.875 7.60135V2.46805C15.875 2.07907 15.718 1.70602 15.4385 1.43097C15.159 1.15592 14.7799 1.0014 14.3847 1.0014H12.1492"  stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
      </svg>

     </div>
     </div>
      `,
  }

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

This example is based on sitesearch-ux-js:


searchstax.addAnswerWidget("searchstax-answer-container", {
    showMoreAfterWordCount: 100,
    templates: {
      main: {
          template: `
        {{#shouldShowAnswer}}
        <div class="searchstax-answer-wrap">
            <div class="searchstax-answer-icon"></div>
            <div>
                <div class="searchstax-answer-container {{#showMoreButtonVisible}}searchstax-answer-show-more{{/showMoreButtonVisible}}">
                    <div class="searchstax-answer-title">Smart Answers</div>
                    {{#shouldShowAnswerError}}
                        <div class="searchstax-answer-error">{{{answerErrorMessage}}}</div>
                    {{/shouldShowAnswerError}}
                    <div class="searchstax-answer-description">
                        {{{fullAnswerFormatted}}}
                        {{^showMoreButtonVisible}}
                            {{#answerLoading}}
                                <div class="searchstax-answer-loading"></div>
                            {{/answerLoading}}
                        {{/showMoreButtonVisible}}
                    </div>

                </div>

                {{#showMoreButtonVisible}}
                    <div class="searchstax-answer-load-more-button-container">
                        {{#answerLoading}}
                            <div class="searchstax-answer-loading"></div>
                        {{/answerLoading}}
                        <button class="searchstax-answer-load-more-button">Read More</button>
                    </div>
                {{/showMoreButtonVisible}}
            </div>
            <div class="searchstax-answer-footer">
                <div id="feedbackWidgetContainer"></div>
                <div class="searchstax-lightweight-widget-separator-inline"></div>
                <p class="searchstax-disclaimer">Generative AI is Experimental</p>
            </div>
            </div>
        {{/shouldShowAnswer}}
        `,
          answerContainerId: ``,
      },
    },
    feedbackwidget: feedbackConfig
  });

Input Widget

The SearchStax Site Search solution’s Input widget provides the search input field with autosuggest/autocomplete capabilities.

Usage

searchstax.addSearchInputWidget("searchstax-input-container", {
    suggestAfterMinChars: 3,
 });

Props

  • suggestAfterMinChars - default 3. Number of characters needed for autosuggest to start triggering
  • hooks.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.
  • hooks.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.
  • templates - template override. look at examples below

inputWidgetTemplate

The templates prop allows customizing the input UI.

It receives the following props:

  • locationEnabled – boolean

inputWidgetAutosuggestTemplate

The templates prop allows customizing the input autosuggest UI.

It receives the following props:

  • term – suggested term

example

 searchstax.addSearchInputWidget("searchstax-input-container", {
    suggestAfterMinChars: 3,
    hooks: {
      afterAutosuggest: function (result: ISearchstaxSuggestResponse) {
        const copy = { ...result };
        return copy;
      },
      beforeAutosuggest: function (props: ISearchstaxSuggestProps) {
        // gets suggestProps, if passed along further autosuggest will execute, if null then event gets canceled
        // props can be modified and passed along
        const propsCopy = { ...props };
        // propsCopy.term = propsCopy.term + '222';
        return propsCopy;
      },
    },
    templates: {
    mainTemplate: {
        template: `
        <div class="searchstax-search-input-container searchstax-search-input-container-new {{#locationEnabled}}searchstax-alternative-render{{/locationEnabled}}">
          <div class="searchstax-search-input-wrapper">
            <input type="text" id="searchstax-search-input" class="searchstax-search-input" placeholder="SEARCH FOR..." aria-label="Search" />
          </div>
          <div id="searchstax-location-container" class="searchstax-location-container"></div>
          <button class="searchstax-spinner-icon" id="searchstax-search-input-action-button" aria-label="search" role="button"></button>
        </div>
        `,
        searchInputId: "searchstax-search-input"
    }
    autosuggestItemTemplate: {
        template: `
        <div class="searchstax-autosuggest-item-term-container">{{{term}}}</div>
        `,
    }
    },
  });

Location Widget

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

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

Usage

function locationDecodeFunction(term: string): Promise<ISearchstaxLocation>{
        return new Promise((resolve) => {
          // make a request to geocoding API to retrieve lat, lon and address and then resolve promise
      resolve({
                  address:'Address',
                  lat: lat,
                  lon: lon,
                  error: false
                });
        });
  }

  function locationDecodeCoordinatesToAddress(lat, lon): Promise<ISearchstaxLocation>{
      return new Promise((resolve) => {
        // make a request to geocoding API to convert lat, lon to address and then resolve promise
      resolve({
                  address:'Address',
                  lat: lat,
                  lon: lon,
                  error: false
                });
      });
    }
 searchstax.addSearchLocationWidget("searchstax-location-container", {
  hooks: {
    locationDecode: locationDecodeFunction,
    locationDecodeCoordinatesToAddress: locationDecodeCoordinatesToAddress
    },
});

Props

  • hooks.locationDecode - callback function to override location decoding
  • hooks.locationDecodeCoordinatesToAddress - callback function to override location decoding
  • templates - see examples below

Template Override

The templates 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

searchstax.addSearchLocationWidget("searchstax-location-container", {
  templates:{
    mainTemplate: {
      template: `
        <div class="searchstax-location-input-container" data-test-id="searchstax-location-input-container">
            <div class="searchstax-location-input-wrapper">
                <span class="searchstax-location-input-label">NEAR</span>
               <div class="searchstax-location-input-wrapper-inner">
                  <input type="text" id="searchstax-location-input" class="searchstax-location-input" placeholder="Zip, Postal Code or City..." aria-label="Search Location Input" data-test-id="searchstax-location-input" />
                  <button id="searchstax-location-get-current-location" class="searchstax-get-current-location-button">Use my current location</button>
                </div>
                {{#shouldShowLocationDistanceDropdown}}
                  <span class="searchstax-location-input-label">WITHIN</span>
                  <select id="searchstax-location-radius-select" class="searchstax-location-radius-select" aria-label="Search Location Radius Select" data-test-id="searchstax-location-radius-select">
                    {{#locationSearchDistanceValues}}
                      <option value="{{value}}" {{#isSelected}}selected{{/isSelected}}>{{label}}</option>
                    {{/locationSearchDistanceValues}}
                  </select>
                {{/shouldShowLocationDistanceDropdown}}
            </div>
        </div>
        `,
      locationInputId: "searchstax-location-input",
      radiusInputId: "searchstax-location-radius-select"
    },
  },
  hooks: {
    locationDecode: locationDecodeFunction,
    locationDecodeCoordinatesToAddress: locationDecodeCoordinatesToAddress
  },
});

Result Widget

The SearchStax Site Search solution’s Results Widget for UX-JS displays the search results.

Usage

searchstax.addSearchResultsWidget("searchstax-results-container", {});

Props

  • renderMethod – either “pagination” or “infiniteScroll”.
  • resultsPerPage – number of results on a page.
  • hooks.afterLinkClick – Callback function invoked when a result link is clicked. Allows modifying the result object.
  • templates - see examples below

Main Template Override

The template prop allows customizing the result UI.

It receives no props:

Search Result Template Override

The template prop allows customizing the result UI.

It receives following 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 template 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

 searchstax.addSearchResultsWidget("searchstax-results-container", {
    templates: {
      mainTemplate: {
      template: `
        <section aria-label="search results container" tabindex="0">
            <div class="searchstax-search-results-container" id="searchstax-search-results-container" data-test-id="searchstax-search-results-container">
                <div class="searchstax-search-results" id="searchstax-search-results"></div>
            </div>
        </section>
            `,
        searchResultsContainerId: "searchstax-search-results",
      },
      searchResultTemplate: {
        template: `
    <a href="{{url}}" data-searchstax-unique-result-id="{{uniqueId}}" data-test-id="searchstax-result-item-link" class="searchstax-result-item-link searchstax-result-item-link-wrapping" tabindex="0" aria-labelledby="title-{{uniqueId}}">
    <div class="searchstax-search-result searchstax-search-result-wrapping {{#thumbnail}} has-thumbnail {{/thumbnail}}">
        {{#promoted}}
            <div class="searchstax-search-result-promoted" data-test-id="searchstax-search-result-promoted"></div>
        {{/promoted}}

        {{#ribbon}}
            <div class="searchstax-search-result-ribbon" data-test-id="searchstax-search-result-ribbon">
            {{{ribbon}}}
            </div>
        {{/ribbon}}

        {{#thumbnail}}
            <img alt="" src="{{thumbnail}}" alt="image" class="searchstax-thumbnail" data-test-id="searchstax-thumbnail">
        {{/thumbnail}}
        <div class="searchstax-search-result-title-container" data-test-id="searchstax-search-result-title-container">
            <h3 class="searchstax-search-result-title" id="title-{{uniqueId}}">{{{title}}}</h3>
        </div>

        {{#paths}}
            <p class="searchstax-search-result-common" tabindex="0" data-test-id="searchstax-search-result-common">
                {{{paths}}}
            </p>
        {{/paths}}

        {{#description}}
            <p tabindex="0" class="searchstax-search-result-description searchstax-search-result-common" data-test-id="searchstax-search-result-description">
                {{{description}}}
            </p>
        {{/description}}

        {{#unmappedFields}}
            {{#isImage}}
                <div class="searchstax-search-result-image-container">
                <img alt="" src="{{value}}" alt="image" class="searchstax-result-image" data-test-id="searchstax-result-image">
                </div>
            {{/isImage}}
            {{^isImage}}
                <p tabindex="0" class="searchstax-search-result-common">
                {{{value}}}
                </p>
            {{/isImage}}
        {{/unmappedFields}}
        {{#distance}}
            <p tabindex="0" class="searchstax-search-result-distance searchstax-search-result-common" data-test-id="searchstax-search-result-distance">
                {{distance}} {{unit}}
            </p>
        {{/distance}}
        </div>
        </a>
            `,
        searchResultUniqueIdAttribute: "data-searchstax-unique-result-id"
      },
      noSearchResultTemplate: {
        template: `
    {{#searchExecuted}}
    <div class="searchstax-no-results-wrap" data-test-id="searchstax-no-results-wrap">
      <div class="searchstax-no-results" data-test-id="searchstax-no-results">
          Showing <strong>no results</strong> for <strong>"{{ searchTerm }}"</strong>
          <br>
          {{#spellingSuggestion}}
              <span>&nbsp;Did you mean <a href="#" aria-label="Did you mean: {{originalQuery}}" class="searchstax-suggestion-term" onclick="searchCallback('{{ spellingSuggestion }}')">{{ spellingSuggestion }}</a>?</span>
          {{/spellingSuggestion}}
      </div>
      <ul class="searchstax-no-results-list" data-test-id="searchstax-no-results-list">
          <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>
          <li>Lost? Click on the ‘X” in the Search Box to reset your search.</li>
      </ul>
    </div>
  {{/searchExecuted}}
            `
      }
    },
    hooks: {
      afterLinkClick: function (result: ISearchstaxParsedResult) {
        // gets result that was clicked, if passed along further functions will execute, if null then event gets canceled
        const propsCopy = { ...result };

        return propsCopy;
      },
    },
  });

Example of infinite scroll render method

 searchstax.addSearchResultsWidget("searchstax-results-container", {
    templates: {
      mainTemplate: {
      template: `
        <section aria-label="search results container" tabindex="0">
            <div class="searchstax-search-results-container" id="searchstax-search-results-container" data-test-id="searchstax-search-results-container">
                <div class="searchstax-search-results" id="searchstax-search-results"></div>
            </div>
        </section>
            `,
        searchResultsContainerId: "searchstax-search-results",
      },
      searchResultTemplate: {
        template: `
    <a href="{{url}}" data-searchstax-unique-result-id="{{uniqueId}}" data-test-id="searchstax-result-item-link" class="searchstax-result-item-link searchstax-result-item-link-wrapping" tabindex="0" aria-labelledby="title-{{uniqueId}}">
    <div class="searchstax-search-result searchstax-search-result-wrapping {{#thumbnail}} has-thumbnail {{/thumbnail}}">
        {{#promoted}}
            <div class="searchstax-search-result-promoted" data-test-id="searchstax-search-result-promoted"></div>
        {{/promoted}}

        {{#ribbon}}
            <div class="searchstax-search-result-ribbon" data-test-id="searchstax-search-result-ribbon">
            {{{ribbon}}}
            </div>
        {{/ribbon}}

        {{#thumbnail}}
            <img alt="" src="{{thumbnail}}" alt="image" class="searchstax-thumbnail" data-test-id="searchstax-thumbnail">
        {{/thumbnail}}
        <div class="searchstax-search-result-title-container" data-test-id="searchstax-search-result-title-container">
            <h3 class="searchstax-search-result-title" id="title-{{uniqueId}}">{{{title}}}</h3>
        </div>

        {{#paths}}
            <p class="searchstax-search-result-common" tabindex="0" data-test-id="searchstax-search-result-common">
                {{{paths}}}
            </p>
        {{/paths}}

        {{#description}}
            <p tabindex="0" class="searchstax-search-result-description searchstax-search-result-common" data-test-id="searchstax-search-result-description">
                {{{description}}}
            </p>
        {{/description}}

        {{#unmappedFields}}
            {{#isImage}}
                <div class="searchstax-search-result-image-container">
                <img alt="" src="{{value}}" alt="image" class="searchstax-result-image" data-test-id="searchstax-result-image">
                </div>
            {{/isImage}}
            {{^isImage}}
                <p tabindex="0" class="searchstax-search-result-common">
                {{{value}}}
                </p>
            {{/isImage}}
        {{/unmappedFields}}
        {{#distance}}
            <p tabindex="0" class="searchstax-search-result-distance searchstax-search-result-common" data-test-id="searchstax-search-result-distance">
                {{distance}} {{unit}}
            </p>
        {{/distance}}
        </div>
        </a>
            `,
        searchResultUniqueIdAttribute: "data-searchstax-unique-result-id"
      },
      noSearchResultTemplate: {
        template: `
    {{#searchExecuted}}
    <div class="searchstax-no-results-wrap" data-test-id="searchstax-no-results-wrap">
      <div class="searchstax-no-results" data-test-id="searchstax-no-results">
          Showing <strong>no results</strong> for <strong>"{{ searchTerm }}"</strong>
          <br>
          {{#spellingSuggestion}}
              <span>&nbsp;Did you mean <a href="#" aria-label="Did you mean: {{originalQuery}}" class="searchstax-suggestion-term" onclick="searchCallback('{{ spellingSuggestion }}')">{{ spellingSuggestion }}</a>?</span>
          {{/spellingSuggestion}}
      </div>
      <ul class="searchstax-no-results-list" data-test-id="searchstax-no-results-list">
          <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>
          <li>Lost? Click on the ‘X” in the Search Box to reset your search.</li>
      </ul>
    </div>
  {{/searchExecuted}}
            `
      }
    },
    renderMethod: 'infiniteScroll',
    resultsPerPage: 10,
    hooks: {
      afterLinkClick: function (result: ISearchstaxParsedResult) {
        // gets result that was clicked, if passed along further functions will execute, if null then event gets canceled
        const propsCopy = { ...result };

        return propsCopy;
      },
    },
  });

Pagination Widget

The SearchStax Site Search solution’s Pagination Widget displays a pagination control for UX-JS.

Usage

searchstax.addPaginationWidget("searchstax-pagination-container", {});

Props

  • templates - see examples below

Multiple Instances

Multiple instances of the Pagination widget can be added by calling the addPaginationWidget method multiple times with different target containers:

searchstax.addPaginationWidget('container1', options1);

searchstax.addPaginationWidget('container2', options2);

Each instance can be configured separately via its options object. This allows for the widget to be added to different locations on the page as needed.

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

 searchstax.addPaginationWidget("searchstax-pagination-container", {
    templates: {
        mainTemplate: {
            template: `
      {{#results.length}}
        <div class="searchstax-pagination-container" data-test-id="searchstax-pagination-container">
          <div class="searchstax-pagination-content">
            <a role="link" class="searchstax-pagination-previous {{#isFirstPage}}disabled{{/isFirstPage}}" aria-disabled="{{#isFirstPage}}true{{/isFirstPage}}{{^isFirstPage}}false{{/isFirstPage}}"  id="searchstax-pagination-previous" data-test-id="searchstax-pagination-previous" tabindex="0" aria-label="Previous Page">< Previous</a>
            <div class="searchstax-pagination-details" data-test-id="searchstax-pagination-details">
              {{startResultIndex}} - {{endResultIndex}} of {{totalResults}}
            </div>
              <a role="link" class="searchstax-pagination-next {{#isLastPage}}disabled{{/isLastPage}}" aria-disabled="{{#isLastPage}}true{{/isLastPage}}{{^isLastPage}}false{{/isLastPage}}" data-test-id="searchstax-pagination-next" id="searchstax-pagination-next" tabindex="0" aria-label="Next Page">Next ></a>
          </div>
        </div>
      {{/results.length}}
      `,
            previousButtonClass: "searchstax-pagination-previous",
            nextButtonClass: "searchstax-pagination-next"
        },
        infiniteScrollTemplate: {
            template: `
      {{#results.length}}
        <div class="searchstax-pagination-container" data-test-id="searchstax-pagination-container">
          <div class="searchstax-pagination-content">
            <a role="link" class="searchstax-pagination-previous {{#isFirstPage}}disabled{{/isFirstPage}}" aria-disabled="{{#isFirstPage}}true{{/isFirstPage}}{{^isFirstPage}}false{{/isFirstPage}}"  id="searchstax-pagination-previous" data-test-id="searchstax-pagination-previous" tabindex="0" aria-label="Previous Page">< Previous</a>
            <div class="searchstax-pagination-details" data-test-id="searchstax-pagination-details">
              {{startResultIndex}} - {{endResultIndex}} of {{totalResults}}
            </div>
              <a role="link" class="searchstax-pagination-next {{#isLastPage}}disabled{{/isLastPage}}" aria-disabled="{{#isLastPage}}true{{/isLastPage}}{{^isLastPage}}false{{/isLastPage}}" data-test-id="searchstax-pagination-next" id="searchstax-pagination-next" tabindex="0" aria-label="Next Page">Next ></a>
          </div>
        </div>
      {{/results.length}}
      `,
            loadMoreButtonClass: "searchstax-pagination-load-more"
        }
    },
  });

Facets Widget

The SearchStax Site Search solution’s Facets Widget for UX-JS displays faceted filters for search.

Facet Selection and Order

Facet lists are configured and ordered on the Site Search Faceting Tab.

Usage

 searchstax.addFacetsWidget("searchstax-facets-container", {
    facetingType: "and",
    itemsPerPageDesktop: 3,
    itemsPerPageMobile: 99,
 });

Multiple Instances

Multiple instances of the Facets widget can be added by calling the addFacetsWidget method multiple times with different target containers:

searchstax.addFacetsWidget('container1', options1);

searchstax.addFacetsWidget('container2', options2);

Each instance can be configured separately via its options object. This allows for the widget to be added to different locations on the page as needed.

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
  • templates - see examples below

Main Template Desktop Override

Main wrapper template for desktop facets display.

It receives following props from IFacetsTemplateData

Main Template Mobile Override

Main wrapper template for mobile facets display.

It receives following props from IFacetsTemplateData

Show More Button Container Override

Template for show more button

It receives following props:

  • showingAllFacets - boolean true if showing all facets

Facet Item Container Template Override

Template for facet item container.

It receives following props:

  • label - label of facet

Clear Facets Template Override

Template for clear facets.

It receives following props:

  • shouldShow - boolean, true if it should be displayed

Facet Item Template Override

Template for facet item.

It receives following props:

  • disabled - boolean, true if disabled
  • isChecked - boolean, true if checked
  • value - string, value of facet
  • count - number of items for that facet

Filter By Template Override

Template for filter by.

It receives no props

Selected Facets Template Override

Template for selected facets.

It receives following props:

  • value - string, value of facet
  • count - number of items for that facet

Example

 searchstax.addFacetsWidget("searchstax-facets-container", {
    facetingType: "and",
    itemsPerPageDesktop: 3,
    itemsPerPageMobile: 99,
    templates: {
        mainTemplateDesktop: {
            template: `
      {{#hasResultsOrExternalPromotions}}
        <div class="searchstax-facets-container-desktop"></div>
      {{/hasResultsOrExternalPromotions}}
      `,
            facetsContainerId: "",
        },
        mainTemplateMobile: {
            template: `
        <div class="searchstax-facets-pills-container">
          <div class="searchstax-facets-pills-selected">
          </div>
        </div>

        <div class="searchstax-facets-mobile-overlay {{#overlayOpened}} searchstax-show{{/overlayOpened}}" data-test-id="searchstax-facets-mobile-overlay">
          <div class="searchstax-facets-mobile-overlay-header">
            <div class="searchstax-facets-mobile-overlay-header-title">Filter By</div>
            <div class="searchstax-search-close" tabindex="0" aria-label="close overlay" role="button" data-test-id="searchstax-search-close"></div>
          </div>
          <div class="searchstax-facets-container-mobile"></div>
          <button class="searchstax-facets-mobile-overlay-done" data-test-id="searchstax-facets-mobile-overlay-done">Done</button>
        </div>
      `,
            facetsContainerClass: `searchstax-facets-container-mobile`,
            closeOverlayTriggerClasses: ["searchstax-facets-mobile-overlay-done","searchstax-search-close",],
            filterByContainerClass: `searchstax-facets-pills-container`,
            selectedFacetsContainerClass: `searchstax-facets-pills-selected`,
        },
        showMoreButtonContainerTemplate: {
            template: `
      <div class="searchstax-facet-show-more-container" data-test-id="searchstax-facet-show-more-container">
      {{#showingAllFacets}}
        <div class="searchstax-facet-show-less-button searchstax-facet-show-button" tabindex="0" data-test-id="searchstax-facet-show-less-button" data-focus="{{focusId}}" role="button">less</div>
      {{/showingAllFacets}}
      {{^showingAllFacets}}
        <div class="searchstax-facet-show-more-button  searchstax-facet-show-button" tabindex="0" data-test-id="searchstax-facet-show-more-button" data-focus="{{focusId}}" role="button">more {{onShowMoreLessClick}}</div>
      {{/showingAllFacets}}
    </div>
      `,
            showMoreButtonClass: `searchstax-facet-show-more-container`,
        },
        facetItemContainerTemplate: {
            template: `
      <div>
        <div class="searchstax-facet-title-container" data-test-id="searchstax-facet-title-container">
            <div class="searchstax-facet-title" aria-label="Facet group: {{label}}" tabindex="0" role="button">
            {{label}}
            </div>
            <div class="searchstax-facet-title-arrow active"></div>
        </div>
        <div class="searchstax-facet-values-container"></div>
      </div>
      `,
            facetListTitleContainerClass: `searchstax-facet-title-container`,
            facetListContainerClass: `searchstax-facet-values-container`,
        },
        clearFacetsTemplate: {
            template: `
      {{#shouldShow}}
        <div class="searchstax-facets-pill searchstax-clear-filters searchstax-facets-pill-clear-all" tabindex="0" role="button" data-test-id="searchstax-facets-pill-clear-all">
        <div class="searchstax-facets-pill-label">Clear Filters</div>
        </div>
      {{/shouldShow}}
      `,
            containerClass: `searchstax-facets-pill-clear-all`,
        },
        facetItemTemplate: {
            template: `
      <div class="searchstax-facet-input">
        <input type="checkbox" class="searchstax-facet-input-checkbox" data-test-id="searchstax-facet-input-checkbox" {{#disabled}}disabled{{/disabled}} {{#isChecked}}checked{{/isChecked}} aria-label="{{value}} {{count}}" tabindex="0"/>
      </div>
      <div class="searchstax-facet-value-label" data-test-id="searchstax-facet-value-label">{{value}}</div>
      <div class="searchstax-facet-value-count" data-test-id="searchstax-facet-value-count">({{count}})</div>
      `,
            inputCheckboxClass: `searchstax-facet-input-checkbox`,
            checkTriggerClasses: ["searchstax-facet-value-label","searchstax-facet-value-count",],
        },
        filterByTemplate: {
            template: `
      <div class="searchstax-facets-pill searchstax-facets-pill-filter-by" tabindex="0" role="button" data-test-id="searchstax-facets-pill-filter-by" >
        <div class="searchstax-facets-pill-label">Filter By</div>
      </div>
      `,
            containerClass: `searchstax-facets-pill-filter-by`,
        },
        selectedFacetsTemplate: {
            template: `
      <div class="searchstax-facets-pill searchstax-facets-pill-facets" tabindex="0" role="button" data-test-id="searchstax-facets-pill-facets">
        <div class="searchstax-facets-pill-label">{{value}} ({{count}})</div>
        <div class="searchstax-facets-pill-icon-close"></div>
      </div>
      `,
            containerClass: `searchstax-facets-pill-facets`,
        },

    },
  });

SearchFeedback Widget

The SearchStax Site Search solution’s Feedback Widget displays search feedback and stats for UX-JS.

Usage

searchstax.addSearchFeedbackWidget("search-feedback-container", {});

Multiple Instances

Multiple instances of the SearchFeedback widget can be added by calling the addSearchFeedbackWidget method multiple times with different target containers:

searchstax.addSearchFeedbackWidget('container1', options1);

searchstax.addSearchFeedbackWidget('container2', options2);

Each instance can be configured separately via its options object. This allows for the widget to be added to different locations on the page as needed.

Props

  • templates - see examples below

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

searchstax.addSearchFeedbackWidget("search-feedback-container", {
    templates: {
      main: {
          template: `
        {{#searchExecuted}}
            <a href="#searchstax-search-results" data-test-id="searchstax-skip" class="searchstax-skip">Skip to results section</a>
            <h4 class="searchstax-feedback-container" data-test-id="searchstax-feedback-container">
              {{#hasResults}}
                 <span> Showing <b>{{startResultIndex}} - {{endResultIndex}}</b> </span> of <b>{{totalResults}}</b> results {{#searchTerm}} for "<b>{{searchTerm}}</b>" {{/searchTerm}}
                  <div class="searchstax-feedback-container-suggested" data-test-id="searchstax-feedback-container-suggested">
                    {{#autoCorrectedQuery}}
                      Search instead for <a href="#" aria-label="Search instead for: {{originalQuery}}" class="searchstax-feedback-original-query" data-test-id="searchstax-feedback-original-query">{{originalQuery}}</a>
                    {{/autoCorrectedQuery}}
                  </div>
                {{/hasResults}}
            </h4>
        {{/searchExecuted}}
        `,
          originalQueryClass: `searchstax-feedback-original-query`
      }
    },
  });

RelatedSearches widget

The SearchStax Site Search solution’s Related Searches Widget displays related searches for UX-JS.

Usage

  searchstax.addRelatedSearchesWidget("searchstax-related-searches-container", {
     relatedSearchesURL: "URL",
     relatedSearchesAPIKey: "KEY"
  })

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
  • templates - see examples below

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 Template Override

Related Search template.

It receives following props:

  • related_search - string, related searc
  • last - boolean, true if last related search

Example

searchstax.addRelatedSearchesWidget("searchstax-related-searches-container", {
     relatedSearchesURL: "URL",
     relatedSearchesAPIKey: "KEY",
    templates: {
      main: {
          template: `
        {{#hasRelatedSearches}}
            <div class="searchstax-related-searches-container" data-test-id="searchstax-related-searches-container" id="searchstax-related-searches-container">
                Related searches: <span id="searchstax-related-searches"></span>
                {{#relatedSearches}}
                <span class="searchstax-related-search">

                </span>
            {{/relatedSearches}}
            </div>
        {{/hasRelatedSearches}}
        `,
          relatedSearchesContainerClass: `searchstax-related-search`,
      },
      relatedSearch: {
          template: `
        <span class="searchstax-related-search searchstax-related-search-item" data-test-id="searchstax-related-search-item" aria-label="Related search: {{related_search}}" tabindex="0">
            {{ related_search }}{{^last}}<span>,</span>{{/last}}
        </span>
        `,
          relatedSearchContainerClass: `searchstax-related-search-item`,
      },
    },
  });

ExternalPromotions widget

SearchStax Site Search solution’s External Promotions Widget displays external promotions for UX-JS.

Usage

  searchstax.addExternalPromotionsWidget("searchstax-external-promotions-layout-container", {})

Props

  • templates - see examples below

Main Template Override

Main template for external promotions.

It receives following props:

  • hasExternalPromotions - boolean, true if has external promotions

External promotion Template Override

Template for external promotion item.

It receives following props:

  • url - url of external promotion
  • uniqueId - unique id
  • name - name of promotion
  • description - description

Example

searchstax.addExternalPromotionsWidget("searchstax-external-promotions-layout-container",  {
    templates: {
      mainTemplate: {
          template: `
        {{#hasExternalPromotions}}
            <div class="searchstax-external-promotions-container" id="searchstax-external-promotions-container" data-test-id="searchstax-external-promotions-container">
                 External promotions go here
            </div>
        {{/hasExternalPromotions}}
    `,
          externalPromotionsContainerId: `searchstax-external-promotions-container`,
      },
      externalPromotion: {
          template: `
        <div class="searchstax-external-promotion searchstax-search-result" data-test-id="searchstax-external-promotion">
            <div class="icon-elevated"></div>
            {{#url}}
            <a href="{{url}}" data-searchstax-unique-result-id="{{uniqueId}}" class="searchstax-result-item-link" data-test-id="searchstax-result-item-link"></a>
            {{/url}}
            <div class="searchstax-search-result-title-container">
                <span class="searchstax-search-result-title" data-test-id="searchstax-search-result-title">{{name}}</span>
            </div>
            {{#description}}
            <p class="searchstax-search-result-description searchstax-search-result-common" data-test-id="searchstax-search-result-description">
            {{description}}
            </p>
            {{/description}}
            {{#url}}
            <p class="searchstax-search-result-description searchstax-search-result-common">
            {{url}}
            </p>
            {{/url}}
        </div>
        `,
      },
    },
  });

Sorting Widget

The SearchStax Site Search solution’s Sorting Widget allows sorting of search results for UX-JS.

Usage

  searchstax.addSearchSortingWidget("search-sorting-container", {});

Props

  • templates - see examples below

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

searchstax.addSearchSortingWidget("search-sorting-container", {
    templates: {
      main: {
          template: `
      {{#searchExecuted}}
        {{#hasResultsOrExternalPromotions}}
        <div class="searchstax-sorting-container" data-test-id="searchstax-sorting-container">
            <label class="searchstax-sorting-label" data-test-id="searchstax-sorting-label" for="searchstax-search-order-select">Sort By</label>
            <select id="searchstax-search-order-select" class="searchstax-search-order-select" data-test-id="searchstax-search-order-select" >
            {{#sortOptions}}
                <option value="{{key}}">
                {{value}}
                </option>
            {{/sortOptions}}
            </select>
        </div>
        {{/hasResultsOrExternalPromotions}}
      {{/searchExecuted}}
      `,
          selectId: `searchstax-search-order-select`
      }
    },
  });

Template overrides

Templates use mustache templating. For more info see https://github.com/janl/mustache.js

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

Data Flow Subscriptions

All variables are observables that have these functions:

$observable.subscribe((var) => {})
$observable.setValue(value)
$observable.getValue()

Loading change subscription

subscribing to loading event observable is available at

searchstax.dataLayer.$loadingChange.subscribe((data) => {})
searchstax.dataLayer.$loadingChange.setValue(data)
const data = searchstax.dataLayer.$loadingChange.getValue()

$loadingChange observable is of type: boolean

Search metadata subscription

subscribing to search metadata event observable is available at

searchstax.dataLayer.$searchResultsMetadata.subscribe((data) => {})
searchstax.dataLayer.$searchResultsMetadata.setValue(data)
const data = searchstax.dataLayer.$searchResultsMetadata.getValue()

$searchResultsMetadata observable is of type: ISearchstaxSearchMetadata and can be used for custom pagination implementation along with afterSearch hook

Search pagination data subscription

subscribing to pagination data event observable is available at

searchstax.dataLayer.$paginationData.subscribe((data) => {})
searchstax.dataLayer.$paginationData.setValue(data)
const data = searchstax.dataLayer.$paginationData.getValue()

$paginationData observable is of type: IPaginationData and can be used for custom pagination implementation along with afterSearch hook

Data Calculations

At any moment data calculation object is accessible with various variables aimed to help build templates in a cleaner way.

Data calculations

Data calculations can be accessed through

searchstax.dataLayer.parsedData.data

parsedData.data is of type: ISearchstaxParsedData