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

# CompareBar

> Shows selected products and sends the selected records to the chat widget for an agent to compare.

For more information, see [Agent Studio](https://www.algolia.com/doc/guides/algolia-ai/agent-studio).

```tsx Signature theme={"system"}
<CompareBar
  configurationId={string}
  // Optional props
  minItems={number}
  maxItems={number}
  transformItems={function}
  itemComponent={function}
  classNames={object}
  translations={object}
/>
```

## Import

```jsx JavaScript icon=code theme={"system"}
import { CompareBar } from "react-instantsearch";
```

## About this widget

Use `CompareBar` to let users compare products with an Agent Studio agent.
The widget renders a comparison bar with the products users selected for comparison and a **Compare** button.
When users select **Compare**,
the widget opens the [`Chat`](https://www.algolia.com/doc/api-reference/widgets/chat/react) widget on the same index and sends a comparison request with the selected records attached.
The widget clears the selection after sending the request.
The chat displays the agent's comparison of the attached records without showing the request as a user message.

The widget doesn't include controls for selecting products.
Add a **Compare** checkbox to each product in your [`Hits`](https://www.algolia.com/doc/api-reference/widgets/hits/react) component.
Use `useInstantSearch().indexRenderState.compare` to read and update the shared selection, as shown in the [example](#examples).
To build a custom comparison bar or **Compare** button, use the [`useCompare`](#hook) Hook.
All `CompareBar` components and `useCompare` Hooks in the same `InstantSearch` component share the same selection,
so the toggles and comparison bar update together.

The comparison bar stays hidden while the selection is empty.
The comparison bar is an [entry point](https://www.algolia.com/doc/api-reference/widgets/chat/react.md#param-disable-trigger-validation) for the chat, so you don't need a [`ChatTrigger`](https://www.algolia.com/doc/api-reference/widgets/chat-trigger/react) widget when you use both `CompareBar` and `Chat`.

The widget requires a comparison configuration, which controls the comparison goal and instructions.
Create it in the Agent Studio dashboard and pass its ID as [`configurationId`](#param-configuration-id).

See also: [Compare products in chat](https://www.algolia.com/doc/guides/algolia-ai/agent-studio/how-to/product-comparison.md)

## Examples

```jsx JavaScript icon=code expandable theme={"system"}
import React from "react";
import { liteClient as algoliasearch } from "algoliasearch/lite";
import {
  Chat,
  CompareBar,
  Hits,
  InstantSearch,
  SearchBox,
  useInstantSearch,
} from "react-instantsearch";
import "instantsearch.css/components/chat.css";

const searchClient = algoliasearch("ALGOLIA_APPLICATION_ID", "ALGOLIA_SEARCH_API_KEY");

function Hit({ hit }) {
  // The selection `CompareBar` owns. It's undefined until the bar mounts.
  const { indexRenderState } = useInstantSearch();
  const { isSelected, toggleItem, canAddItems } =
    indexRenderState.compare ?? {};
  const selected = isSelected?.(hit.objectID) ?? false;

  return (
    <article>
      <h2>{hit.name}</h2>
      <label>
        <input
          type="checkbox"
          checked={selected}
          disabled={!toggleItem || (!selected && !canAddItems)}
          onChange={() => toggleItem?.(hit)}
        />
        Compare
      </label>
    </article>
  );
}

function App() {
  return (
    <InstantSearch indexName="instant_search" searchClient={searchClient}>
      <SearchBox />
      <Hits hitComponent={Hit} />
      <CompareBar
        minItems={2}
        maxItems={3}
        configurationId="CONFIGURATION_ID"
      />
      <Chat agentId="AGENT_ID" />
    </InstantSearch>
  );
}
```

## Props

**configurationId** `string` *required*

The ID of the comparison configuration that controls how the agent compares products.
Create comparison configurations in the **Components** section of your agent in the Agent Studio dashboard.
For more information, see [Compare products in chat](https://www.algolia.com/doc/guides/algolia-ai/agent-studio/how-to/product-comparison.md).

The widget sends `__ALGOLIA_COMPARISON_<configurationId>__` as the user message,
with `comparison_configuration_id` and `selected_products` as [per-turn context](https://www.algolia.com/doc/guides/algolia-ai/agent-studio/how-to/turn-context.md).
`selected_products` holds the selected records as a JSON string, with internal attributes such as `_highlightResult` removed.

Agent Studio replaces the placeholder with the configured agent instructions, and the chat doesn't show a user message for it.
If the configuration doesn't exist or is turned off,
the placeholder reaches the agent unchanged, so only set the ID of an enabled configuration.

```jsx JavaScript icon=code theme={"system"}
<CompareBar configurationId="CONFIGURATION_ID" />
```

**minItems** `number` (default: 2)

The minimum number of products users must select before they can compare.
The **Compare** button is unavailable until users select this number of products.
The value must be at least `2`.

Set `minItems` to the **Minimum products** value in your comparison configuration.

```jsx JavaScript icon=code theme={"system"}
<CompareBar minItems={2} />
```

**maxItems** `number` (default: 3)

The maximum number of products users can select.
When the selection reaches this limit, the widget ignores attempts to add more products and shows a hint.
The value must be greater than or equal to [`minItems`](#param-min-items).

Set `maxItems` to the **Maximum products** value in your comparison configuration.

```jsx JavaScript icon=code theme={"system"}
<CompareBar maxItems={4} />
```

**transformItems** `(items: CompareItem[]) =\> CompareItem[]`

A function that receives the selected records and returns the records to display in the comparison bar.
The widget sends these transformed records to the agent when users select **Compare**.
Use this function to remove long attributes, such as product descriptions.

Return one record for each selected record and preserve its `objectID`.
The selection itself, including `isSelected` and the limits, uses the original records.

```jsx JavaScript icon=code theme={"system"}
<CompareBar
  transformItems={(items) =>
    items.map(({ description, ...item }) => item)
  }
/>
```

**itemComponent** `(props: \{ item: CompareItem \}) =\> JSX.Element`

A component to replace the label of each selected item.
It receives the selected record as the `item` prop.

By default, the label is the record's `name` or `title`, falling back to its `objectID`.

```jsx JavaScript icon=code theme={"system"}
<CompareBar
  itemComponent={({ item }) => (
    <>
      <img src={item.image} alt="" width="24" height="24" />
      <span>{item.name}</span>
    </>
  )}
/>
```

**classNames** `Partial\<CompareBarClassNames\>`

The [CSS classes you can override](https://www.algolia.com/doc/guides/building-search-ui/widgets/customize-an-existing-widget/react.md#style-your-widgets) and pass to the widget's elements.
It's useful to style widgets with class-based CSS frameworks like [Bootstrap](https://getbootstrap.com) or [Tailwind CSS](https://tailwindcss.com).

* `root`. The root element of the widget.
* `header`. The header element.
* `title`. The title element.
* `count`. The selection count element.
* `list`. The list of selected items.
* `item`. Each selected item.
* `itemLabel`. The label of each selected item.
* `itemRemove`. The button that removes an item from the selection.
* `hint`. The hint shown when users select fewer than `minItems` or reach `maxItems`.
* `actions`. The container of the action buttons.
* `clearButton`. The button that clears the selection.
* `compareButton`. The button that starts the comparison.

```jsx JavaScript icon=code theme={"system"}
<CompareBar
  classNames={{
    root: "MyCustomCompareBar",
    compareButton: [
      "MyCustomCompareBarButton",
      "MyCustomCompareBarButton--subclass",
    ],
  }}
/>
```

**translations** `Partial\<CompareBarTranslations\>`

A dictionary of translations to customize the UI text and support internationalization.

* `title` (`string`). The title of the comparison bar. The default is `Compare`.
* `countText` (`(count: number, maxItems: number) => string`). The selection count. The default is `${count} of ${maxItems}`.
* `compareButtonText` (`(count: number) => string`). The label of the **Compare** button. The default is `Compare ${count}`.
* `clearButtonText` (`string`). The label of the **Clear all** button.
* `removeItemLabel` (`(itemLabel: string) => string`). The accessible label of each remove button. The default is `Remove ${itemLabel} from comparison`.
* `minItemsHint` (`(minItems: number) => string`). The hint shown while the selection is below `minItems`. The default is `Select at least ${minItems} products to compare.`
* `limitReachedHint` (`string`). The hint shown when the selection reaches `maxItems`. The default is `Compare limit reached — remove a product to add another.`.

```jsx JavaScript icon=code theme={"system"}
<CompareBar
  translations={{
    title: "Your comparison",
    compareButtonText: (count) => `Compare ${count} products`,
  }}
/>
```

## Hook

Use the `useCompare` Hook to build a custom comparison bar or **Compare** button.
It accepts the same props as `CompareBar`: `configurationId` (required), `minItems`, `maxItems`, and `transformItems`.
It returns:

* `items` (`CompareItem[]`).
  The selected records, in selection order, after `transformItems`.
  Each item has at least an `objectID`.
* `isSelected` (`(objectID: string) => boolean`).
  Whether the record with this `objectID` is in the selection.
* `addItem` (`(item: CompareItem) => void`).
  Adds a record to the selection.
  It doesn't add the record if it's already selected or the selection has reached `maxItems`.
  The label uses `name` or `title`, falling back to `objectID`.
  Each record must have an `objectID`.
* `removeItem` (`(objectID: string) => void`).
  Removes the record with this `objectID` from the selection.
* `toggleItem` (`(item: CompareItem) => void`).
  Adds the record to the selection when it isn't selected, and removes it otherwise.
* `clearItems` (`() => void`).
  Empties the selection.
* `canAddItems` (`boolean`).
  Whether the selection is below `maxItems`.
* `canCompare` (`boolean`).
  Whether the selection has reached `minItems`.
* `minItems` (`number`).
  The resolved [`minItems`](#param-min-items) value.
* `maxItems` (`number`).
  The resolved [`maxItems`](#param-max-items) value.
* `compare` (`() => boolean`).
  Opens the `Chat` widget on the same index, sends the compare request with the selected records attached, and clears the selection.
  Returns `true` when it submits the message and `false` when the selection is below `minItems`, the page doesn't have a `Chat` widget, or the chat is busy.

Every `useCompare` Hook and `CompareBar` component in the same `InstantSearch` shares the selection.
Pass the same `configurationId`, `minItems`, and `maxItems` to each so they use the same configuration and limits.
Each `useCompare` call mounts a widget, so for a toggle on every hit, read the selection from `useInstantSearch().indexRenderState.compare` instead, as in the [example](#examples).

```jsx JavaScript icon=code expandable theme={"system"}
import { useCompare } from "react-instantsearch";

function CustomCompareBar() {
  const { items, canCompare, compare, removeItem, clearItems } = useCompare({
    minItems: 2,
    maxItems: 3,
    configurationId: "CONFIGURATION_ID",
  });

  if (items.length === 0) {
    return null;
  }

  return (
    <div>
      <ul>
        {items.map((item) => (
          <li key={item.objectID}>
            {item.name}
            <button type="button" onClick={() => removeItem(item.objectID)}>
              Remove
            </button>
          </li>
        ))}
      </ul>
      <button type="button" onClick={() => clearItems()}>
        Clear all
      </button>
      <button type="button" disabled={!canCompare} onClick={() => compare()}>
        Compare {items.length}
      </button>
    </div>
  );
}
```
