---
title: "Widget templates"
slug: "widget-templates"
abstract: "Overview of Sitecore Search widget templates in the JS SDK."
---
# 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.

- [Widget](https://doc.sitecore.com/search/en/developers/search-js-sdk-for-react/js-sdk-reference/components/widget.html "Widget")
- [BannerWidget](https://doc.sitecore.com/search/en/developers/search-js-sdk-for-react/js-sdk-reference/components/bannerwidget.html "BannerWidget")
- [HTMLBlockWidget](https://doc.sitecore.com/search/en/developers/search-js-sdk-for-react/js-sdk-reference/components/htmlblockwidget.html "HTMLBlockWidget")

> [!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](https://www.npmjs.com/package/@sitecore-search/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. ```js
    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](https://www.npmjs.com/package/@sitecore-search/cli) package.
    - The `ArticleModel` for the entity type `article `used in the request query.
    - `RecommendationProps` with the necessary properties for the widget.
    - `InitialState`
2. ```js
    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.

    | Property | Type | Description |
    | --- | --- | --- |
    | `title` | string | String used as a title for the widget. |
    | `itemsToDisplay` | integer | Maximum number of items in the response and display in the widget.<br><br>Default: 4 |

3. ```js
    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. ```js
    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. ```js
    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. ```js
    const RecommendationBasicWidget = widget(RecommendationBasicHorizontalStyledComponent, WidgetDataType.RECOMMENDATION,"content");
    ```

    [`widget`](https://doc.sitecore.com/search/en/developers/search-js-sdk-for-react/js-sdk-reference/high-order-functions/widget-function.html "widget function") 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. ```text
    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.

```js
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;
```