# Reactions Customization

In this example, we'll demonstrate how to override the SDK's default reaction set, which is exported as [`defaultReactionOptions`](https://github.com/GetStream/stream-chat-react/blob/v11.0.0/src/components/Reactions/reactionOptions.tsx) variable. We'll replace the default set with up and down arrows, simulating an up/down voting feature.

Under the hood, our [`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) components render individual emoji components defined in the `reactionOptions`. Therefore, the array with your custom reactions needs to conform to `ReactionOptions` type:

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

Let's construct a simple option list consisting of `'arrow-up'` and `'arrow-down'` native emojis. To override the default set we'll need to pass this option list to the component context through `Channel` component so that our default components can pick it up:

```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">

Please note that types missing from the option list won't be registered and might lead to sub-optimal user experience.

</admonition>

If you need to, you can pass these options to each of the default components individually (component props are prioritized even when the `reactionOptions` are routed through the `Channel`):

```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">

While `ReactionSelector` can display a subset of available reactions (to limit what certain users can react with), the `ReactionsList` should have the whole list available if applicable.

</admonition>

<gallery>

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

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

</gallery>

### Custom Reaction Handler

If you need to adjust the default behavior you can certainly do so by replacing reaction handler while keeping the default component intact:

```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 the component context
export const WrappedChannel = ({ children }) => (
  <Channel ReactionSelector={CustomReactionSelector}>{children}</Channel>
);
```

### Read More

See more on customization options in [_Introducing new reactions_](/chat/docs/sdk/react/release-guides/upgrade-to-v11#introducing-new-reactions/) section of our _Upgrade to v11_ guide.

---

This page was last updated at 2025-08-15T14:16:07.849Z.

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