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

# Dynamic product carousels

> Display search results in carousels. The dynamic carousel lets you change the list of carousels from the dashboard without editing the frontend.

export const Records = () => <Tooltip tip="A record is a searchable object in an Algolia index. Each record consists of named attributes." cta="Algolia records" href="/doc/guides/sending-and-managing-data/prepare-your-data#algolia-records">
    records
  </Tooltip>;

export const Index = () => <Tooltip tip="An Algolia index is a searchable dataset that consists of records and configuration settings. These settings define how the records are searched and ranked.">
    index
  </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 product carousel with 'Popular' and 'Best Rated' sections, each showing six items 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-programmatic-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 four files:

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

### 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-programmatic-ecommerce-demo?file=/src/ecommerce_transformed_dataset.json), located in the `src/` folder.

In addition to the two indices used to store the product dataset, the dynamic solution uses a third Algolia index called `e_commerce_transformed_config` to define the content of the carousels and their order on the page. With this index, you manage your carousels directly in the dashboard without needing to change your frontend code. You can download [the JSON of the `e_commerce_transformed_config` index](https://codesandbox.io/s/github/algolia/solutions/tree/master/content-carousel-programmatic-ecommerce-demo?file=/src/e_commerce_transformed_config.json), located in the `src/` folder.

### Configure each carousel

To dynamically generate the carousels, you can store each carousel's configuration in the `e_commerce_transformed_config` index.
For this demo, the index has five <Records />, one for each carousel.
Each record has attributes that define the `title` of the carousel, the index in `indexName`, and any query parameters in `configure` pertinent to the carousel.

The [carousel section](#creating-the-carousels) walks you through four typical carousels. They all rely on the records in the `e_commerce_transformed_config` index. Here's an example record:

```json JSON icon=braces theme={"system"}
{
  "title": "Popular",
  "indexName": "e_commerce_transformed",
  "configure": {
    "hitsPerPage": 10
  },
  "order": 1,
  "objectID": "popular"
}
```

You need to set up `order` as a custom ranking attribute. Doing so orders the shelves on the frontend. You learn about the other attributes as you go through the tutorial.

### Adapt the HTML

In your `index.html` file, add the following `div` as a placeholder for your dynamically generated carousels.

```html HTML icon=code-xml theme={"system"}
<div id="carousel-container" class="carousel-container"></div>
```

### Render the carousels

This section explains how to render the carousels dynamically, by creating a new [`index`](/doc/api-reference/widgets/index-widget/js) widget for each carousel.

* Use `src/main.js` to render the carousel widgets.
* Use `src/carousel.js` to define the carousel widget.

#### Define how to display the carousels

Define the display logic for every carousel in `src/carousel.js`. This file creates the widget that you append to the `carousel-container` defined in `index.html`.

Create a `renderCarousel` function that targets the containers and appends them with the hits you want to display:

* Target the carousel container.
* Create an `<h2>` header that displays the title of the carousel.
* 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 movie you want to display.

Here is the full rendering code.

```js JavaScript icon=code theme={"system"}
export const carousel = connectHits(function renderCarousel(
  { widgetParams: { container, title }, hits },
  isFirstRender,
) {
  if (isFirstRender) {
    const section = document.createElement("section");
    container.appendChild(section);
    const h2 = document.createElement("h2");
    h2.innerText = title;
    section.appendChild(h2);
    const ul = document.createElement("ul");
    ul.classList.add("carousel-list-container");
    section.appendChild(ul);
  }

  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("");
});
```

#### Render the `carousel` widgets

The following function returns an array of all carousel widgets.

```js JavaScript icon=code theme={"system"}
function getCarousels() {
  return searchClient
    .initIndex("e_commerce_transformed_config")
    .search("", {
      attributesToHighlight: [],
      attributesToRetrieve: ["title", "indexName", "configure"],
    })
    .then((res) => res.hits);
}
```

Next, loop through the array and do the following:

1. Carry out a search on the index associated with the carousel, using any search parameters defined in the widget.
2. Create the widget with the results obtained.
3. Append the `carousel` widget to the `carouselContainer`.

Here is the full loop.

```js JavaScript icon=code theme={"system"}
getCarousels().then((carousels) => {
  const container = document.querySelector("#carousel-container");

  search.addWidgets(
    carousels.map((carouselConfig) => {
      const carouselContainer = document.createElement("div");

      const indexWidget = index({
        indexName: carouselConfig.indexName,
        indexId: carouselConfig.objectID,
      });

      if (carouselConfig.configure) {
        indexWidget.addWidgets([
          configure({
            ...carouselConfig.configure,
            // replace user token with the user's one if set by configure
            userToken: carouselConfig.configure.userToken
              ? getUserToken()
              : undefined,
          }),
        ]);
      }

      indexWidget.addWidgets([
        carousel({
          title: carouselConfig.title,
          container: carouselContainer,
        }),
      ]);

      container.appendChild(carouselContainer);

      return indexWidget;
    }),
  );

  // only start _after_ carousels have been added
  search.start();
});
```

This is all the coding you need to do. The rest of this solution describes how to use the records in `e_commerce_transformed_config` to create the different carousels.

### Creating 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).

You need to define each of these carousels as records in the `e_commerce_transformed_config` index. To do so, you can add the JSON snippets in the following sections to that index. You don't have to do any further frontend development.

#### Most popular products

This carousel displays the most popular products.

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

Place the following record in the `e_commerce_transformed_config` index.

```json JSON icon=braces theme={"system"}
{
  "title": "Popular",
  "indexName": "e_commerce_transformed",
  "configure": {
    "hitsPerPage": 10
  },
  "order": 1,
  "objectID": "popular"
}
```

#### Best rated products

This carousel displays best rated products.

The JSON is the same as the [carousel that displays the most popular products](#most-popular-products). The difference is the targeted index: the replica called `e_commerce_transformed_rating_desc`. This replica ranks its records differently:

* It uses `ratings` as a [sort-by](/doc/guides/managing-results/refine-results/sorting/how-to/sort-by-attribute) attribute.
* It uses `ratingsNumber` as [custom ranking](/doc/guides/managing-results/must-do/custom-ranking/how-to/configure-custom-ranking) attribute.

Place the following record in the `e_commerce_transformed_config` index.

```json JSON icon=braces theme={"system"}
{
  "title": "Best Rated",
  "indexName": "e_commerce_transformed_rating_desc",
  "configure": {
    "hitsPerPage": 10
  },
  "order": 2,
  "objectID": "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 query.
The unique part here is that the rendering code in the [creating a render function](#render-the-carousels) section conditions the display with `onSale=true`.

Place the following record in the `e_commerce_transformed_config` index.

```json JSON icon=braces theme={"system"}
{
  "title": "On Sale",
  "indexName": "e_commerce_transformed",
  "configure": {
    "hitsPerPage": 10,
    "filters": "onSale:true"
  },
  "order": 3,
  "objectID": "on-sale"
}
```

#### 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 drop-down menu, click **Manual Editor**.

4. In the **Condition(s)** section, click **Context** and enter `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.

Place the following record in the `e_commerce_transformed_config` index.

```json JSON icon=braces theme={"system"}
{
  "title": "Gifts for Black Friday",
  "indexName": "e_commerce_transformed",
  "configure": {
    "hitsPerPage": 10,
    "ruleContexts": "carousel_black_friday"
  },
  "order": 5,
  "objectID": "gifts-for-black-friday"
}
```

### Next steps

**Add more carousels**. Now that you know how to set up product carousels, you can create a variety of carousels for your project. This helps improve user engagement with your products.
