# Reaction components

> **Info:** This is release candidate documentation for **Stream Chat React SDK v15**. For the latest stable version, see the [latest version (v14)](https://getstream.io/chat/docs/sdk/react/).

The reaction components draw a message's reactions and let the user add them:

- `ReactionSelector`: the quick reactions, opened from the smiley button next to a message or from **Add reaction** in its menu;
- `ReactionSelectorExtendedList`: the full list, behind the selector's **+** button and the dialog's add button;
- `MessageReactions`: the reactions on the message, with their counts;
- `MessageReactionsDetail`: the dialog that lists who reacted.

Each is an override key, and `reactionOptions` sets the reactions they offer. [Reactions](https://getstream.io/chat/docs/sdk/react/v15/features/messaging/reactions/) explains how they work together, and how to change the reactions on offer, their style, their order and what a reaction does.

## Best practices

- Set `reactionOptions` once, around the whole app, so the selector, the message and the dialog show the same reactions.
- Wrap a replacement for `ReactionSelector` in `forwardRef`. The key is typed as a `forwardRef` component, so a plain function doesn't type-check.
- Declare `sortReactions` outside the component. A new comparator on every render sorts the reactions again on every render.

## Customization

The SDK renders the `ReactionSelector` key in a dialog next to the message. From the smiley button it passes no props, from the menu only `dialogId`, and it never passes a `ref`. This replacement puts the default selector in a frame of its own:

```tsx
import { forwardRef } from "react";
import type { ReactionSelectorProps } from "stream-chat-react";
import { ReactionSelector, WithComponents } from "stream-chat-react";

const FramedReactionSelector = forwardRef<
  HTMLDivElement,
  ReactionSelectorProps
>(function FramedReactionSelector(props, ref) {
  return (
    <div className="framed-reaction-selector" ref={ref}>
      <ReactionSelector {...props} />
    </div>
  );
});

const overrides = { ReactionSelector: FramedReactionSelector };

export const App = () => (
  <WithComponents overrides={overrides}>
    {/* the rest of the app */}
  </WithComponents>
);
```

[Changing what a reaction does](https://getstream.io/chat/docs/sdk/react/v15/features/messaging/reactions/#changing-what-a-reaction-does) replaces the handler the same way.

## ReactionSelector props

| Prop             | Type                                                                 | Default                           | Description                                                             |
| ---------------- | -------------------------------------------------------------------- | --------------------------------- | ----------------------------------------------------------------------- |
| `dialogId`       | `string`                                                             | `ReactionSelector.getDialogId()`  | The id of the dialog the selector closes after a pick.                  |
| `handleReaction` | `(reactionType: string, event: BaseSyntheticEvent) => Promise<void>` | `handleReaction` from the context | Adds or removes a reaction. Used by the selector and its extended list. |
| `own_reactions`  | `ReactionResponse[]`                                                 | `message.own_reactions`           | The user's reactions, which the selector shows as pressed.              |

The selector closes after a pick when the list's `closeReactionSelectorOnClick` is set. Its **+** button shows only when `reactionOptions` has `extended` reactions.

`ReactionSelectorExtendedList` takes the same props. It renders nothing without `extended` reactions. The default isn't exported by name; it's `ReactionSelector.ExtendedList`.

## MessageReactions props

| Prop                     | Type                                                                                | Default                                             | Description                                                                                                       |
| ------------------------ | ----------------------------------------------------------------------------------- | --------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `capLimit`               | `{ clustered?: number; segmented?: number }`                                        | `{ clustered: 5, segmented: 4 }`                    | How many reaction types show. Segmented reactions not at the top aren't capped.                                   |
| `flipHorizontalPosition` | `boolean`                                                                           | `false`                                             | Adds the `str-chat__message-reactions--flipped-horizontally` class, to anchor the reactions on the other side.    |
| `handleFetchReactions`   | `(reactionType?: string, sort?: SortParamRequest[]) => Promise<ReactionResponse[]>` | `handleFetchReactions` from the context             | Loads the users for the dialog.                                                                                   |
| `own_reactions`          | `ReactionResponse[]`                                                                | `message.own_reactions`                             | The user's reactions.                                                                                             |
| `reaction_groups`        | `Record<string, ReactionGroupResponse>`                                             | `message.reaction_groups`                           | One summary per reaction type: its count and when it was first and last used. The reactions shown come from here. |
| `reactionDetailsSort`    | `SortParamRequest[]`                                                                | `reactionDetailsSort` from the context              | The order of users in the dialog.                                                                                 |
| `reactions`              | `ReactionResponse[]`                                                                | `message.latest_reactions`                          | The recent reactions, used for the names of the users who reacted.                                                |
| `reverse`                | `boolean`                                                                           | `false`                                             | Declared, but has no effect. The default `MessageUI` passes `true`.                                               |
| `sortReactions`          | `ReactionsComparator`                                                               | `sortReactions` from the context, else by first use | Orders the reaction types.                                                                                        |
| `verticalPosition`       | `'top' \| 'bottom' \| null`                                                         | `'top'`                                             | Adds the class that puts the reactions above or below the bubble. `null` adds neither.                            |
| `visualStyle`            | `'clustered' \| 'segmented' \| null`                                                | `'clustered'`                                       | `clustered` is one button with the total count; `segmented` is one button per type, with its count.               |

Only the reaction types in `reactionOptions` show, and a message with none of them renders nothing. Clicking the reactions opens `MessageReactionsDetail`, showing all reactions in the clustered style and the clicked type in the segmented one. A message with more than 1000 reactions doesn't open it.

`ReactionsComparator` isn't exported. Type a comparator as `MessageListProps['sortReactions']`; it compares two summaries with `reactionType`, `reactionCount`, `firstReactionAt`, `lastReactionAt` and `isOwnReaction`.

## MessageReactionsDetail props

`MessageReactions` renders the dialog with every prop but `dialogId`, `handleReaction`, `own_reactions` and `sort`.

| Prop                           | Type                                                                                | Default                                                           | Description                                                                                               |
| ------------------------------ | ----------------------------------------------------------------------------------- | ----------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| `reactions`                    | `ReactionSummary[]`                                                                 | required                                                          | The reaction types to list at the top, with their counts and emoji.                                       |
| `selectedReactionType`         | `string \| null`                                                                    | required                                                          | The type whose users are listed. `null` lists every user, each with the emoji they picked.                |
| `handleFetchReactions`         | `(reactionType?: string, sort?: SortParamRequest[]) => Promise<ReactionResponse[]>` | `handleFetchReactions` from the context                           | Loads the users, 25 at a time, up to 1000.                                                                |
| `handleReaction`               | `(reactionType: string, event: BaseSyntheticEvent) => Promise<void>`                | `handleReaction` from the context                                 | Used by the add step. Removing the user's own reaction always uses the context's handler.                 |
| `onSelectedReactionTypeChange` | `(reactionType: string \| null) => void`                                            |                                                                   | Called when the user picks a type, and with `null` when they pick it again.                               |
| `own_reactions`                | `ReactionResponse[]`                                                                | `message.own_reactions`                                           | Passed to the extended list of the add step.                                                              |
| `reactionDetailsSort`          | `SortParamRequest[]`                                                                | from the context, else `[{ direction: -1, field: 'created_at' }]` | The order of users, sent with the query.                                                                  |
| `reactionGroups`               | `Record<string, ReactionGroupResponse>`                                             |                                                                   | The summaries, used to go back to all users when the user removes the last reaction of the selected type. |
| `sort`                         | `SortParamRequest[]`                                                                |                                                                   | Declared, but not read. Use `reactionDetailsSort`.                                                        |
| `totalReactionCount`           | `number`                                                                            |                                                                   | Shown as "5 reactions" at the top. Without it, there's no count.                                          |
| `dialogId`                     | `string`                                                                            |                                                                   | Declared through the selector's props, but not read.                                                      |

The add button shows only when `reactionOptions` has `extended` reactions, and opens `ReactionSelectorExtendedList` in the dialog. While users load, the dialog renders the `LoadingIndicator` key, or `MessageReactionsDetailLoadingIndicator` by default. That skeleton is exported for a dialog of your own.

## Related exports

| Export                                                                                                         | What it is                                                                                                                                                                                   |
| -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `reactionOptions` key, `ReactionOptions`                                                                       | The reactions on offer: `quick` for the selector, `extended` for the full list. See [The reactions on offer](https://getstream.io/chat/docs/sdk/react/v15/features/messaging/reactions/#the-reactions-on-offer). |
| `defaultReactionOptions`                                                                                       | The default set.                                                                                                                                                                             |
| `emojiToUnicode`, `unicodeToEmoji`                                                                             | Convert between an emoji and the `unicode` code of a reaction option.                                                                                                                        |
| `mapEmojiMartData(data)`                                                                                       | Turns the `@emoji-mart/data` set into `extended` reactions.                                                                                                                                  |
| `ReactionSelector.getDialogId({ messageId, threadList })`, `MessageReactionsDetail.getDialogId({ messageId })` | The ids of the two dialogs, to open or close them through a dialog manager.                                                                                                                  |

## Hooks

- `useMessageContext()` gives `handleReaction`, `handleFetchReactions`, `sortReactions` and `reactionDetailsSort`.
- `useReactionHandler(message)` and `useReactionsFetcher(message)` build the context's two handlers, for a component outside a message. See [Message hooks](https://getstream.io/chat/docs/sdk/react/v15/reference/hooks/message-hooks/).
- `useComponentContext()` returns `reactionOptions` and the reaction overrides in effect.

---

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react/v15/component-reference/message/reaction-components/](https://getstream.io/chat/docs/sdk/react/v15/component-reference/message/reaction-components/).