> ## Documentation Index
> Fetch the complete documentation index at: https://algolia.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Static product carousels

> Divide search results into rows, where each row displays a different product category like most popular or trending items.

export const SearchQuery = () => <Tooltip tip="The text users enter into a search box. In the Search API, this corresponds to the query parameter. A search query is often used with filters, facets, and other parameters, but these aren't part of the query text itself.">
    search query
  </Tooltip>;

Carousels (also called shelves, lanes, or aisles) organize your products and results within categories.
Rather than overwhelming users with a large grid of items,
carousels group items into scannable rows like "most popular," "best rated," and "on sale."

Carousels are highly customizable: you can adjust their categories, order, and content.

[<img src="https://mintcdn.com/algolia/uAYFrBCMSmYQz381/images/guides/solutions/static-product-carousels.jpg?fit=max&auto=format&n=uAYFrBCMSmYQz381&q=85&s=1e8e1437dc763b93edf8110425c4095c" alt="Screenshot of a 'Popular' and 'Best Rated' product carousel showing electronics with images, names, prices, and ratings." width="2540" height="1440" data-path="images/guides/solutions/static-product-carousels.jpg" />](https://codesandbox.io/s/github/algolia/solutions/tree/master/content-carousel-static-ecommerce-demo)

## Before you begin

This guide requires the Algolia Personalization feature and [InstantSearch.js](/doc/guides/building-search-ui/getting-started/js).

<Callout icon="credit-card" color="#c084fc">
  This feature isn't available on every plan.
  Refer to your [pricing plan](https://www.algolia.com/pricing) to see if it's included.
</Callout>

## Implementation guide

This guide shows you how to display products in five different carousels:
"Popular," "Best rated," "On sale," "These might interest you," and "Gifts for Black Friday."

You need these three files:

* `index.html`
* `src/main.js`
* `src/style.css`

<Steps>
  <Step title="Indices to display the carousels">
    You need two Algolia indices containing the [product dataset](https://codesandbox.io/s/github/algolia/solutions/tree/master/content-carousel-static-ecommerce-demo?file=/src/ecommerce_transformed_dataset.json):

    * A primary index, with a [custom ranking](/doc/guides/managing-results/must-do/custom-ranking) on the `popularity` attribute of the products. Name this index `e_commerce_transformed`.
    * A [replica](/doc/guides/managing-results/refine-results/sorting/how-to/creating-replicas) of the `e_commerce_transformed` index, with a custom ranking on the `popularity` attribute. Name this index `e_commerce_transformed_rating_desc`. Use this index for the "best rated" carousel.

    You can download [the JSON of the `e_commerce_transformed` index](https://codesandbox.io/s/github/algolia/solutions/tree/master/content-carousel-personalized-demo?file=/src/personalized_movies_carousel_config.json), located in the `src/` folder.
  </Step>

  <Step title="Adapt the HTML">
    In your `index.html` file, add a container for each carousel.

    ```html HTML icon=code-xml theme={"system"}
    <div class="carousel-container">
      <h2>Popular</h2>
      <div id="carousel-most-popular"></div>
      <h2>Best Rated</h2>
      <div id="carousel-best-rated"></div>
      <h2>On Sale</h2>
      <div id="carousel-on-sale"></div>
      <h2>These might interest you</h2>
      <div id="carousel-personalized"></div>
      <h2>Gifts for Black Friday</h2>
      <div id="carousel-black-friday-sale"></div>
    </div>
    ```
  </Step>

  <Step title="Create a render function">
    In the `src/main.js` file, create a `renderCarousel` function that targets the containers, and replaces them with the hits you want to display:

    * Target the carousel container.
    * Add a `<ul>` tag in the container when you render the carousel for the first time.
    * Inside the `<ul>` element, add `<li>` tags for each product you want to display.

    ```js JavaScript icon=code theme={"system"}
    const renderCarousel = ({ widgetParams, hits }, isFirstRender) => {
      const container = document.querySelector(widgetParams.container);

      if (isFirstRender) {
        const carouselUl = document.createElement("ul");
        carouselUl.classList.add("carousel-list-container");
        container.appendChild(carouselUl);
      }

      container.querySelector("ul").innerHTML = hits
        .map(
          (hit) => `
          <li>
              ${hit.onSale ? `<img class="on-sale" src="${onSaleImg}" alt="">` : ""}
              <img src="${hit.image}" alt="${hit.name}">
              <span>${hit.brand}</span>
              <a href="#">
                <h3>${hit.name}</h3>
              </a>
              <p>${[...Array(hit.rating === 0 ? 1 : hit.rating).keys()]
                .map(() => "⭐️")
                .join("")}  (${hit.ratingsNumber})</p>
                <p><span ${
                  hit.onSale ? 'style="text-decoration: line-through"' : ""
                }>$${hit.price}</span> ${
                  hit.onSale
                    ? `<span style="color: red">$${hit.newPrice}</span>`
                    : ""
                }</p>
          </li>
          
          `,
        )
        .join("");
    };
    ```
  </Step>

  <Step title="Tell InstantSearch to use the render function">
    Use [`connectHits`](/doc/api-reference/widgets/hits/js#customize-the-ui-with-connecthits) to tell InstantSearch to use `renderCarousel` to render hits.

    ```js JavaScript icon=code theme={"system"}
    const carousel = connectHits(renderCarousel);
    ```
  </Step>

  <Step title="Create an index widget">
    Create an [`index`](/doc/api-reference/widgets/index-widget/js) widget for each of the five carousels and add them to the page with the [`addWidgets`](/doc/api-reference/widgets/instantsearch/js#param-add-widgets) method.

    Here is the framework, to be filled in by the code in the following sections.

    ```js JavaScript icon=code theme={"system"}
    search.addWidgets([
      // Carousel #1
      index(/* Most popular */).addWidgets(/* ... */),

      // Carousel #2
      index(/* Best rated */).addWidgets(/* ... */),

      // Carousel #3
      index(/* On sale */).addWidgets(/* ... */),

      // Carousel #4
      index(/* These might interest you */).addWidgets(/* ... */),

      // Carousel #5
      index(/* Gifts for Black Friday */).addWidgets(/* ... */),
    ]);
    ```
  </Step>
</Steps>

### Create the carousels

This tutorial offers five examples of carousels. Some apply different sorting strategies. Others require [Personalization](/doc/guides/personalization/classic-personalization/what-is-personalization) or [Rules](/doc/guides/managing-results/rules/rules-overview).

They each contain the code that you place in the framework described in the previous section.

#### Most popular products

This carousel displays the most popular products.

The code targets the `e_commerce_transformed` index that sorts results by popularity. The code limits the number of results to `8`, and displays the carousel in the correct container: `#carousel-most-popular`. You also need to provide the `indexID` property, because other carousels target the same index.

```js JavaScript icon=code theme={"system"}
index({
  indexName: "e_commerce_transformed",
  indexId: "popular",
}).addWidgets([
  configure({
    hitsPerPage: 8,
  }),
  carousel({
    container: "#carousel-most-popular",
  }),
]);
```

#### Best rated products

This carousel displays best rated products.

The code is similar to the [carousel that displays the most popular products](#most-popular-products). The main difference is the index you target. You have to target the replica index called `e_commerce_transformed_rating_desc`, which ranks products on the `popularity` attribute.

```js JavaScript icon=code theme={"system"}
index({
  indexName: "e_commerce_transformed_rating_desc",
  indexId: "best-rated",
}).addWidgets([
  configure({
    hitsPerPage: 8,
  }),
  carousel({
    container: "#carousel-best-rated",
  }),
]);
```

#### On sale items

This carousel displays a list of products that are on sale. To do this, it uses the `onSale` attribute.

Like the first two carousels, it sets up the <SearchQuery />.
The unique part here is that the rendering code conditions the display with `onSale=true`.

```js JavaScript icon=code theme={"system"}
index({
  indexName: "e_commerce_transformed",
  indexId: "perso",
}).addWidgets([
  configure({
    hitsPerPage: 8,
    filters: "onSale:true",
  }),
  carousel({
    container: "#carousel-on-sale",
  }),
]);
```

#### These might interest you

This carousel displays a list of products personalized to each user's taste. To do this, it leverages Algolia's [Personalization](/doc/guides/personalization/classic-personalization/what-is-personalization) feature. Make sure your [plan](https://www.algolia.com/pricing/) has access to Personalization before trying to implement this.

For Personalization to work, you need to configure two extra search parameters for the carousel:

* [`enablePersonalization`](/doc/api-reference/api-parameters/enablePersonalization) to enable Personalization for this search.
* [`userToken`](/doc/api-reference/api-parameters/userToken) to specify the user you personalize for.

```js JavaScript icon=code theme={"system"}
index({
  indexName: "e_commerce_transformed",
  indexId: "personalized",
}).addWidgets([
  configure({
    hitsPerPage: 8,
    enablePersonalization: true,
    userToken: "samsung_fan", // Dynamically update user token
  }),
  carousel({
    container: "#carousel-personalized",
  }),
]);
```

#### Gifts for Black Friday

This carousel displays products that users can offer as gifts on Black Friday. To accomplish this, you need to create a [Rule](/doc/guides/managing-results/rules/rules-overview), either in the dashboard or with the API.

##### Using the dashboard

To create this rule in the dashboard, follow these steps:

1. Select the **Rules** section from the left sidebar menu in the [Algolia dashboard](https://dashboard.algolia.com/rules).
2. Under the heading **Rules**, select the index you are adding a rule to.
3. Select **Create your first rule** or **New rule**. In the  menu, click the **Manual Editor** option.
4. In the **Condition(s)** section, click **Context**, enter the text `carousel_black_friday`.
5. In the **Consequence(s)** section:

   * Click the **Add consequence** button and select **Add Query Parameter**.

   * In the input field that appears, enter the following JSON search parameter.

     ```json JSON icon=braces theme={"system"}
     {
       "filters": "onSale:true AND popularity>=21000"
     }
     ```

   * Click the **Add consequence** button and select **Pin an item**.

   * Find the product '1319385', click '2', and press `Enter`.

   * Find the product '5197004', click '3', and press `Enter`.

   * Find the product '5327500', click '4', and press `Enter`.

   * Find the product '4826902', click '7', and press `Enter`.

   * Find the product '8945804', click '8', and press `Enter`.

   * Find the product '4374300', click '12', and press `Enter`.
6. Save your changes.

##### Using an API client

If you use the API to create your Rule, use the [`saveRule`](/doc/libraries/sdk/v1/methods/save-rule) method with the following Rule structure:

```json JSON icon=braces theme={"system"}
{
  "enabled": true,
  "tags": ["visual-editor"],
  "description": "gift black friday / high popularity + On sale",
  "conditions": [
    {
      "anchoring": "is",
      "pattern": "",
      "alternatives": false,
      "context": "carousel_black_friday"
    }
  ],
  "consequence": {
    "promote": [
      {
        "objectIDs": ["4826902"],
        "position": 6
      },
      {
        "objectIDs": ["5327500"],
        "position": 3
      },
      {
        "objectIDs": ["1319385"],
        "position": 1
      },
      {
        "objectIDs": ["4374300"],
        "position": 11
      },
      {
        "objectIDs": ["5197004"],
        "position": 2
      },
      {
        "objectIDs": ["8945804"],
        "position": 7
      }
    ],
    "params": {
      "filters": "\"onSale\":\"true\" AND \"popularity\">=21000"
    },
    "filterPromotes": true
  },
  "objectID": "qr-1606321675053"
}
```

Then, you have to set up the carousel with the `carousel_black_friday` Rule with the correct [context](/doc/guides/managing-results/rules/rules-overview#what-are-contexts). Do this using the [`ruleContexts`](/doc/api-reference/api-parameters/ruleContexts) parameter.

```js JavaScript icon=code theme={"system"}
index({
  indexName: "e_commerce_transformed",
  indexId: "black-friday-gifts",
}).addWidgets([
  configure({
    hitsPerPage: 8,
    ruleContexts: "carousel_black_friday",
  }),
  carousel({
    container: "#carousel-black-friday-sale",
  }),
]);
```

### Next steps

* **Add more carousels**. Now that you know how to set up content carousels, you can create a variety of carousels for your project. This helps improve user engagement with your content.
* **Add dynamic carousels**. The current solution defined the list of carousels directly in the code, which means that, if you want to change the list, you need to change the code. The [dynamic carousels](/doc/guides/solutions/ecommerce/browse/product-carousels/dynamic-product-carousels) solution lets you change the list of carousels from the dashboard without needing to change the code.
