Customize Message Reactions

Message reactions are a crucial part of a chat applications. The SDK comes with built-in support for adding reactions to messages.

Supported Reaction types

You can customize the supported types of reactions for your application using the supportedReactions prop of the Channel component.

It expects an array of object with keys Icon and type. You can use ReactionData type for additional type safety.

An example of how you can pass the supportedRections to the Channel component could be:

import { Text } from "react-native";
import { ReactionData } from "stream-chat-react-native";

const supportedReactions: ReactionData[] = [
  { type: "happy", Icon: () => <Text>😄</Text> },
  { type: "sad", Icon: () => <Text>😦</Text> },
  { type: "love", Icon: () => <Text>❤️</Text> },
  { type: "angry", Icon: () => <Text>😠</Text> },
  { type: "haha", Icon: () => <Text>😆</Text> },
];

<Channel supportedReactions={supportedReactions}>
  {/* Underlying MessageList and MessageInput components */}
</Channel>;

Reaction List Position

For the display of the reactions in the message we support both top and bottom view which can be customized using the reactionListPosition prop of the Channel component.

<Channel reactionListPosition="bottom">
  {/* Underlying MessageList and MessageInput components */}
</Channel>

Top Reactions

Bottom Reactions

Top ReactionsBottom Reactions

Enforce unique reactions

We allow customizing the reaction behaviour for a message, such that a message can only have a single type of reaction as reacted by the user.

To do this, you can enable the enforceUniqueReaction prop in the Channel component.

<Channel enforceUniqueReaction>
  {/* Underlying MessageList and MessageInput components */}
</Channel>

Customizing message Reaction List components

The message reaction list component on the message when the message has some reactions can be customized using the following components:

  • ReactionListTop
  • ReactionListBottom

These components can be customized by passing a custom UI implementation to the Channel component as follows:

Bottom ReactionList customization

import { Pressable, StyleSheet } from "react-native";
import { Channel, useMessageContext } from "stream-chat-react-native";

const CustomReactionListBottomComponent = () => {
  const {
    handleReaction,
    onPress,
    onLongPress,
    reactions,
    showMessageOverlay,
  } = useMessageContext<StreamChatGenerics>();

  return (
    <View style={styles.container}>
      {reactions?.map((reaction) => {
        const { type, Icon } = reaction;
        return (
          <Pressable
            onLongPress={(event) => {
              if (onLongPress) {
                onLongPress({
                  defaultHandler: () => {
                    if (handleReaction) {
                      showMessageOverlay(true);
                    }
                  },
                  emitter: "reactionList",
                  event,
                });
              }
            }}
            onPress={(event) => {
              onPress({
                defaultHandler: () => {
                  if (handleReaction) {
                    handleReaction(reaction.type);
                  }
                },
                emitter: "reactionList",
                event,
              });
            }}
            key={type}
          >
            {Icon ? <Icon /> : null}
          </Pressable>
        );
      })}
    </View>
  );
};

const ChannelScreen = () => {
  return (
    <Channel
      reactionListPosition="bottom"
      ReactionListBottom={CustomReactionListBottomComponent}
    >
      {/* Underlying MessageList and MessageInput components */}
    </Channel>
  );
};

const styles = StyleSheet.create({
  container: {
    borderRadius: 4,
    flexDirection: "row",
    marginVertical: 2,
  },
});

Customizing Reaction Picker component

The UI for the Reaction Picker can be customized by passing a custom MessageReactionPicker component in the Channel component.

Message Reaction Picker customization

import { FlatList, Pressable, StyleSheet } from "react-native";
import { Channel, useMessageContext } from "stream-chat-react-native";

const CustomMessageReactionPicker = () => {
  const { supportedReactions } = useMessagesContext<StreamChatGenerics>();
  const { dismissOverlay, handleReaction } =
    useMessageContext<StreamChatGenerics>();

  const renderItem = ({ item }: { item: ReactionData }) => {
    return (
      <Pressable
        key={item.type}
        onPress={() => {
          if (handleReaction) {
            handleReaction(item.type);
          }
          dismissOverlay();
        }}
      >
        {item.Icon ? <item.Icon /> : null}
      </Pressable>
    );
  };

  return (
    <FlatList
      columnWrapperStyle={styles.container1}
      data={supportedReactions}
      keyExtractor={(item) => item.type}
      numColumns={6}
      renderItem={renderItem}
    />
  );
};

const ChannelScreen = () => {
  return (
    <Channel
      reactionListPosition="bottom"
      MessageReactionPicker={CustomMessageReactionPicker}
    >
      {/* Underlying MessageList and MessageInput components */}
    </Channel>
  );
};

const styles = StyleSheet.create({
  container: {
    justifyContent: "space-evenly",
    marginVertical: 8,
  },
});

Customizing Message Reactions by user list component

We display the list of the reactions reacted by users in the channel in the MessageUserReactions component and each of the item in the list using the MessageUserReactionsItem and the avatar using the MessageUserReactionsAvatar component.

Message User Reactions customization

import { useMemo } from "react";
import { Image, FlatList, StyleSheet, Text, View } from "react-native";
import { ReactionSortBase } from "stream-chat";
import {
  Channel,
  Reaction,
  useFetchReactions,
  useMessageContext,
} from "stream-chat-react-native";

const CustomMessageUserReactions = () => {
  const { message } = useMessageContext<StreamChatGenerics>();
  const reactionSort: ReactionSortBase = {
    created_at: -1,
  };

  const { reactions: fetchedReactions } = useFetchReactions({
    message,
    sort: reactionSort,
  });

  const reactions = useMemo(
    () =>
      fetchedReactions.map((reaction) => ({
        id: reaction.user?.id,
        image: reaction.user?.image,
        name: reaction.user?.name,
        type: reaction.type,
      })) as Reaction[],
    [fetchedReactions],
  );

  const renderItem = ({ item }: { item: Reaction }) => {
    const Icon = supportedReactions?.find(
      (supportedReaction) => supportedReaction.type === item.type,
    )?.Icon;
    return (
      <View style={styles.container}>
        <MessageUserReactionsAvatar reaction={item} />
        <Text style={styles.text}>{item.name}</Text>
        <View style={styles.icon}>{Icon && <Icon />}</View>
      </View>
    );
  };

  return (
    <FlatList
      data={reactions}
      keyExtractor={(item) => item.id}
      renderItem={renderItem}
    />
  );
};

const styles = StyleSheet.create({
  container: {
    flexDirection: "row",
    flexWrap: "wrap",
    marginHorizontal: 16,
    alignItems: "center",
    marginVertical: 8,
  },
  icon: {
    position: "absolute",
    right: 0,
  },
  text: {
    marginHorizontal: 16,
  },
});

Similarly, you can customize the MessageUserReactionsItem and MessageUserReactionsAvatar component.

© Getstream.io, Inc. All Rights Reserved.