1. JS SDK reference

Widget templates

Sitecore Search widgets are dynamic components added to a page or an email message to deliver specific experiences. The primary purpose of a widget is to display content from Search. Unlike content personalization widgets, which only display previously configured content, merchandising widgets can modify data requests based on context or user interactions.

The SearchJS SDK for React package includes the following widget templates that can be instantiated only with a rfk_id. At runtime, the JS SDK requests data for the widgets and supplies them with data required for configuration and display.

Note

Search results, preview search and recommendation widgets are not included in the JS SDK because they need functional React components to be associated with them.

The JS SDK only provides query hooks and high order functions that you can use to create your component or template.

Anatomy of a basic recommendation widget template

In order to understand how widgets are written in UI components CLI package, the code for a styled recommendation widget has been broken down into smaller blocks. Each block is annotated to describe the various elements of a widget template.

  1.  import ( React ) from 'react';
     import { WidgetDataType, useRecommendation, widget, RecommendationInitialState } from '@sitecore-search/react';
     import { Presence } from '@sitecore-search/ui';
     import {
       ArticleCardStyled,
       GridStyled,
       LoaderAnimation,
       LoaderContainer,
       RecommendationContainer,
       TitleStyled,
     } from './styled';
    
     type ArticleModel = {
       id: string;
       name: string;
       author?: string;
       url?: string;
       image_url?: string;
       source_id?: string;
     };
     type RecommendationProps = {
       title?: string;
       itemsToDisplay?: number;
     };
     type InitialState = RecommendationInitialState<'itemsPerPage'>;

    This block incudes the following:

    • Import statements for WidgetDataType enumerator, useRecommendation query hook, and widget function from the Discover JS SDK for React.
    • Import statements for ArticleCardStyled headless primitive UI component from the UI components CLI package.
    • The ArticleModel for the entity type article used in the request query.
    • RecommendationProps with the necessary properties for the widget.
    • InitialState
  2.  export const RecommendationBasic = ({ title = '', itemsToDisplay = 6 }) => {

    This is the declaration of the React UI component for a basic recommendation widget. The following table describes the arguments: title is used in the output, and productsToDisplay is passed in the query.

    PropertyTypeDescription
    titlestringString used as a title for the widget.
    itemsToDisplayintegerMaximum number of items in the response and display in the widget.

    Default: 4
  3.  export const RecommendationBasicHorizontalStyledComponent = ({ title = '', itemsToDisplay = 6 }: RecommendationProps) => {
       const {
         widgetRef,
         actions: { onItemClick },
         queryResult: { isLoading, isFetching, data: { content: articles = [] } = {} },
       } = useRecommendation<ArticleModel, InitialState>({
         state: {
           itemsPerPage: itemsToDisplay,
         },
       });

    To create a recommendation widget, you must use the useRecommendation query hook. This generic response of the query hook includes three objects: action, state and queryResult. In this example, when a product name is clicked, we trigger the onItemClick action from the response. We also extract the articles array from data in the response.

  4.  const loading = !isLoading && !isFetching && articles.length > 0;

    The widget is displayed when the boolean ready evaluated using the query hook response, isLoading, isFetching and products.

  5.  return (
         <RecommendationContainer>
           <Presence present={loading}>
             <LoaderContainer>
               <LoaderAnimation
                 aria-busy={loading}
                 aria-hidden={!loading}
                 focusable="false"
                 role="progressbar"
                 viewBox="0 0 20 20"
               >
                 <path d="M7.229 1.173a9.25 9.25 0 1 0 11.655 11.412 1.25 1.25 0 1 0-2.4-.698 6.75 6.75 0 1 1-8.506-8.329 1.25 1.25 0 1 0-.75-2.385z" />
               </LoaderAnimation>
             </LoaderContainer>
           </Presence>
           {loading && (
             <>
               {title && <TitleStyled>{title}</TitleStyled>}
               <GridStyled ref={widgetRef}>
                 {articles.map((item, index) => (
                   <ArticleCardStyled.Root key={item.id}>
                     <ArticleCardStyled.ImageWrapper>
                       <ArticleCardStyled.Image src={item?.image_url || DEFAULT_IMG_URL} />
                     </ArticleCardStyled.ImageWrapper>
                     <ArticleCardStyled.Content>
                       <ArticleCardStyled.Link
                         href={item.url}
                         onClick={(event) => {
                           event.preventDefault();
                           onItemClick({ id: item.id, index, sourceId: item.source_id });
                         }}
                       >
                         <ArticleCardStyled.Title>{item.name}</ArticleCardStyled.Title>
                         <ArticleCardStyled.Subtitle>{item.author}</ArticleCardStyled.Subtitle>
                       </ArticleCardStyled.Link>
                     </ArticleCardStyled.Content>
                   </ArticleCardStyled.Root>
                 ))}
               </GridStyled>
             </>
           )}
         </RecommendationContainer>
       );

    The HTML returned by this React component describes the display of this simple component. It loops through the articles array and populates the headless ArticleCardStyled primitive UI component. You can only use the attributes in the display that are marked to be included in the response. Unmarked attributes can result in errors.

  6.  const RecommendationBasicWidget = widget(RecommendationBasicHorizontalStyledComponent, WidgetDataType.RECOMMENDATION,"content");

    widget is a high order function that converts the React UI component into a widget component that can be added as a descendant of WidgetsProvider. We also need to provide the widget and the entity types for the results. The query hook used in the React UI component must match the widget type used with the widget function.

  7.  export default RecommendationBasicWidget;

    Export statement of the widget component.

The following is the entire code for the basic recommendation widget. For search results and preview search widgets, use their respective query hooks.

import React from 'react';
import { WidgetDataType, useRecommendation, widget, RecommendationInitialState } from '@sitecore-search/react';
import { Presence } from '@sitecore-search/ui';
import {
  ArticleCardStyled,
  GridStyled,
  LoaderAnimation,
  LoaderContainer,
  RecommendationContainer,
  TitleStyled,
} from './styled';

type ArticleModel = {
  id: string;
  name: string;
  author?: string;
  url?: string;
  image_url?: string;
  source_id?: string;
};
type RecommendationProps = {
  title?: string;
  itemsToDisplay?: number;
};
type InitialState = RecommendationInitialState<'itemsPerPage'>;

export const RecommendationBasicHorizontalStyledComponent = ({ title = '', itemsToDisplay = 6 }: RecommendationProps) => {

  const {
    widgetRef,
    actions: { onItemClick },
    queryResult: { isLoading, isFetching, data: { content: articles = [] } = {} },
  } = useRecommendation<ArticleModel, InitialState>({
    state: {
      itemsPerPage: itemsToDisplay,
    },
  });

  const loading = !isLoading && !isFetching && articles.length > 0;

  return (
    <RecommendationContainer>
      <Presence present={loading}>
        <LoaderContainer>
          <LoaderAnimation
            aria-busy={loading}
            aria-hidden={!loading}
            focusable="false"
            role="progressbar"
            viewBox="0 0 20 20"
          >
            <path d="M7.229 1.173a9.25 9.25 0 1 0 11.655 11.412 1.25 1.25 0 1 0-2.4-.698 6.75 6.75 0 1 1-8.506-8.329 1.25 1.25 0 1 0-.75-2.385z" />
          </LoaderAnimation>
        </LoaderContainer>
      </Presence>
      {loading && (
        <>
          {title && <TitleStyled>{title}</TitleStyled>}
          <GridStyled ref={widgetRef}>
            {articles.map((item, index) => (
              <ArticleCardStyled.Root key={item.id}>
                <ArticleCardStyled.ImageWrapper>
                  <ArticleCardStyled.Image src={item?.image_url || DEFAULT_IMG_URL} />
                </ArticleCardStyled.ImageWrapper>
                <ArticleCardStyled.Content>
                  <ArticleCardStyled.Link
                    href={item.url}
                    onClick={(event) => {
                      event.preventDefault();
                      onItemClick({ id: item.id, index, sourceId: item.source_id });
                    }}
                  >
                    <ArticleCardStyled.Title>{item.name}</ArticleCardStyled.Title>
                    <ArticleCardStyled.Subtitle>{item.author}</ArticleCardStyled.Subtitle>
                  </ArticleCardStyled.Link>
                </ArticleCardStyled.Content>
              </ArticleCardStyled.Root>
            ))}
          </GridStyled>
        </>
      )}
    </RecommendationContainer>
  );
};

const RecommendationStyledWidget = widget(RecommendationBasicHorizontalStyledComponent, WidgetDataType.RECOMMENDATION, "content");

export default RecommendationStyledWidget;
If you have suggestions for improving this article, let us know!