@searchstax-inc/searchstudio-ux-js v1.0.52
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'
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",
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:
advanced data flow subscriptions
Following widgets are available:
Answer Widget
Initialization properties
a. id of container where widget will be rendered
b. Answer widget config object of type: ISearchstaxAnswerConfig
example of answer widget initialization with minimum options
searchstax.addAnswerWidget("searchstax-answer-container", {
showShowMoreAfterWordCount: 100
});example of answer widget initialization with lightweight feedback widget
searchstax.addAnswerWidget("searchstax-answer-container", {
showShowMoreAfterWordCount: 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: {
renderFeedbackWidget: true,
emailOverride: () => '',
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>
`,
}
});example of answer widget initialization without feedback widget
searchstax.addAnswerWidget("searchstax-answer-container", {
showShowMoreAfterWordCount: 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: ``,
},
},
});Input Widget
Initialization properties
a. id of container where widget will be rendered
b. Input widget config object of type: ISearchstaxSearchInputConfig
example of input widget initialization with minimum options
searchstax.addSearchInputWidget("searchstax-input-container", {
suggestAfterMinChars: 3,
});example of input widget initialization with various options
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" data-test-id="searchstax-search-input-container">
<div class="searchstax-search-input-wrapper">
<input type="text" id="searchstax-search-input" class="searchstax-search-input" placeholder="SEARCH FOR..." aria-label="Search" data-test-id="searchstax-search-input" />
<button class="searchstax-spinner-icon" id="searchstax-search-input-action-button" aria-label="search" role="button" data-test-id="searchstax-search-input-action-button"></button>
</div>
</div>
`,
searchInputId: "searchstax-search-input"
}
autosuggestItemTemplate: {
template: `
<div class="searchstax-autosuggest-item-term-container">{{{term}}}</div>
`,
}
},
});Result Widget
Initialization properties
a. id of container where widget will be rendered
b. Result widget config object of type: ISearchstaxSearchResultsConfig
example of results widget initialization with minimum options
searchstax.addSearchResultsWidget("searchstax-results-container", {});example of result widget initialization with various options
searchstax.addSearchResultsWidget("searchstax-results-container", {
templates: {
mainTemplate: {
template: `
<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>
`,
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">
<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">{{{title}}}</h3>
</div>
{{#paths}}
<p class="searchstax-search-result-common" data-test-id="searchstax-search-result-common">
{{{paths}}}
</p>
{{/paths}}
{{#description}}
<p 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 class="searchstax-search-result-common">
{{{value}}}
</p>
{{/isImage}}
{{/unmappedFields}}
</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> 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 result widget initialization with infinite scroll enabled. This will render pagination widget with infiniteScrollTemplate
searchstax.addSearchResultsWidget("searchstax-results-container", {
templates: {
mainTemplate: {
template: `
<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>
`,
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">
<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">{{{title}}}</h3>
</div>
{{#paths}}
<p class="searchstax-search-result-common" data-test-id="searchstax-search-result-common">
{{{paths}}}
</p>
{{/paths}}
{{#description}}
<p 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 class="searchstax-search-result-common">
{{{value}}}
</p>
{{/isImage}}
{{/unmappedFields}}
</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> 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',
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
Initialization properties
a. id of container where widget will be rendered
b. Pagination widget config object of type: ISearchstaxSearchPaginationConfig
example of pagination widget initialization with minimum options
searchstax.addPaginationWidget("searchstax-pagination-container", {});example of pagination widget initialization with various options
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 class="searchstax-pagination-previous {{#isFirstPage}}disabled{{/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 class="searchstax-pagination-next {{#isLastPage}}disabled{{/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 class="searchstax-pagination-previous {{#isFirstPage}}disabled{{/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 class="searchstax-pagination-next {{#isLastPage}}disabled{{/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
Initialization properties
a. id of container where widget will be rendered
b. Facets widget config object of type: ISearchstaxSearchFacetsConfig
example of facets widget initialization with minimum options
searchstax.addFacetsWidget("searchstax-facets-container", {
facetingType: "and",
itemsPerPageDesktop: 3,
itemsPerPageMobile: 99,
});example of facets widget initialization with various options
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">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">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">
{{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
Initialization properties
a. id of container where widget will be rendered
b. SearchFeedback widget config object of type: ISearchstaxSearchFeedbackConfig
example of search feedback widget initialization with minimum options
searchstax.addSearchFeedbackWidget("search-feedback-container", {});example of search feedback widget initialization with various options
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
Initialization properties
a. id of container where widget will be rendered
b. RelatedSearches widget config object of type: ISearchstaxRelatedSearchesConfig
example of search feedback widget initialization with minimum options
searchstax.addRelatedSearchesWidget("searchstax-related-searches-container", {
relatedSearchesURL: "URL",
relatedSearchesAPIKey: "KEY"
})example of search feedback widget initialization with various options
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
Initialization properties
a. id of container where widget will be rendered
b. ExternalPromotions widget config object of type: ISearchstaxExternalPromotionsConfig
example of search feedback widget initialization with minimum options
searchstax.addExternalPromotionsWidget("searchstax-external-promotions-layout-container", {})example of search feedback widget initialization with various options
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
Initialization properties
a. id of container where widget will be rendered
b. Sorting widget config object of type: ISearchstaxSearchSortingConfig
example of sorting widget initialization with minimum options
searchstax.addSearchSortingWidget("search-sorting-container", {});example of sorting widget initialization with various options
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.cssData 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.dataparsedData.data is of type: ISearchstaxParsedData
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
12 months ago
1 year ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago