# Reactions Customization

In this example, we’ll override the SDK’s default reaction set (`defaultReactionOptions`) with up/down arrows to simulate voting.

## Best Practices

- Keep custom reactions aligned with your product’s interaction model.
- Ensure all supported reaction types are included to avoid degraded UI.
- Provide a full set for `ReactionsList` even if the selector shows a subset.
- Prefer custom handlers when changing behavior without replacing UI.
- Test reactions with permissions and moderation policies enabled.

Under the hood, [`ReactionSelector`](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Reactions/ReactionSelector.tsx), [`ReactionsList`](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Reactions/ReactionsList.tsx), [`SimpleReactionsList`](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Reactions/SimpleReactionsList.tsx), and [`ReactionsListModal`](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Reactions/ReactionsListModal.tsx) render emoji components from `reactionOptions`. Your custom array must match `ReactionOptions`:

```tsx
type ReactionOptions = Array<{
  type: string;
  Component: React.ComponentType;
  name?: string;
}>;
```

Let’s build a simple list with `'arrow_up'` and `'arrow_down'` emojis. To override the defaults, pass the list via `Channel` so default components can read it:

```tsx
import { Channel } from "stream-chat-react";

const customReactionOptions = [
  {
    type: "arrow_up",
    Component: () => <>⬆️</>,
    name: "Upwards Black Arrow",
  },
  {
    type: "arrow_down",
    Component: () => <>⬇️</>,
    name: "Downwards Black Arrow",
  },
];

export const WrappedChannel = ({ children }) => (
  <Channel reactionOptions={customReactionOptions}>{children}</Channel>
);
```

<admonition type="note">

If a reaction type is missing from the list, it won’t be registered and can lead to a degraded experience.

</admonition>

You can also pass options directly to the default components (component props override the `Channel` value):

```tsx
import { Channel, ReactionsList, ReactionSelector } from "stream-chat-react";

const CustomReactionsList = (props) => (
  <ReactionsList {...props} reactionOptions={customReactionOptions} />
);

// ReactionSelector component requires forwarded reference
const CustomReactionSelector = forwardRef((props, ref) => (
  <ReactionSelector
    {...props}
    ref={ref}
    reactionOptions={selectorReactionOptions}
  />
));

export const WrappedChannel = ({ children }) => (
  <Channel
    ReactionsList={CustomReactionsList}
    ReactionSelector={CustomReactionSelector}
  >
    {children}
  </Channel>
);
```

<admonition type="note">

`ReactionSelector` can show a subset of reactions, but `ReactionsList` should generally have the full set.

</admonition>

<gallery>

![Custom reactionOptions rendered through ReactionSelector](@chat-sdk/react/v13/_assets/reaction-selector-w-custom-options.png)

![Custom reactionOptions rendered through ReactionsList](@chat-sdk/react/v13/_assets/reactions-list-w-custom-options.png)

</gallery>

### Custom Reaction Handler

To adjust behavior without replacing the UI, provide a custom `handleReaction`:

```tsx
import { Channel, ReactionSelector } from "stream-chat-react";

const CustomReactionSelector = React.forwardRef((props, ref) => {
  const {
    message: { own_reactions: ownReactions = [], id: messageId },
  } = useMessageContext("CustomReactionSelector");
  const { channel } = useChannelStateContext("CustomReactionSelector");

  const handleReaction = useCallback(
    async (reactionType, event) => {
      // your custom logic with default behavior (minus optimistic updates)

      console.log({ event });

      const hasReactedWithType =
        (ownReactions ?? []).some(
          (reaction) => reaction.type === reactionType,
        ) ?? false;

      if (hasReactedWithType) {
        await channel.deleteReaction(messageId, reactionType);
        return;
      }

      await channel.sendReaction(messageId, { type: reactionType });
    },
    [channel, ownReactions, messageId],
  );

  return (
    <ReactionSelector {...props} handleReaction={handleReaction} ref={ref} />
  );
});

// and then just add it to ComponentContext
export const WrappedChannel = ({ children }) => (
  <Channel ReactionSelector={CustomReactionSelector}>{children}</Channel>
);
```

### Read More

See [_Introducing new reactions_](/chat/docs/sdk/react/v11/release-guides/upgrade-to-v11#introducing-new-reactions/) in the v11 upgrade guide for more options.


---

This page was last updated at 2026-04-21T09:53:40.857Z.

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react/v13/guides/theming/reactions/](https://getstream.io/chat/docs/sdk/react/v13/guides/theming/reactions/).