# Custom Message Actions

Message actions appear in the message menu when you long-press a message. You can control them granularly.
By default, the following actions are shown:

![Message Actions](@chat-sdk/react-native/v8/_assets/guides/custom-message-actions/message_actions.png)

## Best Practices

- Start from default actions and selectively remove or reorder to preserve platform expectations.
- Keep action lists short and context-aware (own message vs. others, threads vs. channel).
- Prefer `messageActions` for UI changes and `onLongPressMessage` for custom behavior.
- Ensure destructive actions (delete, ban, mute) are gated by capabilities and confirmations.
- Return `null` for actions you explicitly want to hide instead of leaving them undefined.

Each UI action maps to a [`MessageAction`](#messageaction) object that provides title, icon, handler, and `actionType`.

```tsx
type MessageActionType = {
  action: () => void;
  actionType: enum('blockUser', 'copyMessage', 'deleteMessage', 'deleteForMeMessage', 'editMessage', 'flagMessage', 'markUnread', 'muteUser', 'pinMessage', 'selectReaction', 'reply', 'retry', 'quotedReply', 'threadReply', 'unpinMessage');
  title: string;
  icon?: React.ReactElement;
  titleStyle?: StyleProp<TextStyle>;
};
```

You can customize default actions via props on the [`Channel` component](/chat/docs/sdk/react-native/v8/core-components/channel/). These props are available through `MessagesContext`.

`Channel` accepts a `messageActions` callback to selectively render actions.

The callback receives an object with default [`MessageAction`](#messageaction) objects. Return an array of actions to render in [MessageActionList](/chat/docs/sdk/react-native/v8/core-components/channel#messageactionlist/) inside the message overlay.

Example:

```tsx
messageActions={({
  blockUser, // MessageAction | null;
  copyMessage, // MessageAction | null;
  deleteMessage, // MessageAction | null;
  dismissOverlay, // () => void;
  editMessage, // MessageAction | null;
  error, // boolean;
  flagMessage, // MessageAction | null;
  isThreadMessage, // boolean;
  markUnread, // MessageAction | null;
  muteUser, // MessageAction | null;
  ownCapabilities, // object;
  pinMessage, // MessageAction | null;
  quotedReply, // MessageAction | null;
  retry, // MessageAction | null;
  showMessageReactions, // boolean;
  threadReply, // MessageAction | null;
  unpinMessage, // MessageAction | null;
}) => {
  return []; // Array<MessageAction>
}}
```

## Message Action Object type

### MessageAction

Long-pressing a message opens the menu and renders available actions. `MessageAction` defines a single action button.

#### Example

```tsx
{
  action: () => { /** Some action here */ },
  icon: <PinIcon />,
  title: 'Pin Message',
  titleStyle: { color: 'red' }
}
```

#### Keys and Values

#### `action`

Called when the user presses the action.

| Type     |
| -------- |
| Function |

#### `actionType`

Type of the action performed.

| Type                                                                                                                                                                                                                            |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| enum('blockUser', 'copyMessage', 'deleteMessage', 'deleteMessageForMe', 'editMessage', 'flagMessage', 'markUnread', 'muteUser', 'pinMessage', 'selectReaction', 'reply', 'retry', 'quotedReply', 'threadReply', 'unpinMessage') |

#### `icon`

Icon element for the action button.

| Type          |
| ------------- |
| React Element |

#### `title`

Action button title.

| Type   |
| ------ |
| String |

#### `titleStyle`

Styles for the action title text.

| Type                                                                      |
| ------------------------------------------------------------------------- |
| [`Text Style Props`](https://reactnative.dev/docs/text-style-props#props) |

### MessagePressableHandlerPayload

`MessagePressableHandlerPayload` is passed to handlers like `onLongPressMessage` and `onPressMessage`.

#### Example

```tsx
{
  actionHandlers: {
    deleteMessage: [function],
    editMessage: [function],
    quotedReply: [function],
    resendMessage: [function],
    showMessageOverlay: [function],
    toggleBanUser: [function],
    toggleMuteUser: [function],
    toggleReaction: [function],
  },
  additionalInfo: [object],
  message: [message object],
}
```

#### Keys and values

#### `additionalInfo`

Additional message pressable handler info.

| Type   |
| ------ |
| Object |

#### `actionHandlers`

Action handler functions for message actions. Use these to perform actions on interaction.

- `deleteMessage`
- `editMessage`
- `quotedReply`
- `resendMessage`
- `showMessageOverlay`
- `toggleBanUser`
- `toggleMuteUser`
- `toggleReaction` (takes `reactionType` as parameter)

```tsx
<Channel onLongPressMessage={({ defaultHandlers }) => defaultHandlers.quotedReply()}
```

| Type   |
| ------ |
| Object |

#### `message`

Message object that was interacted with.

```tsx
<Channel onLongPressMessage={({ message }) => console.log(message.id, message.text)}
```

| Type   |
| ------ |
| Object |

## How to conditionally render message actions

The following example demonstrates how to:

- Only show the "Copy Message" and "Edit Message" actions from the default message actions.
- Show "Edit Message" only for messages from the current user.

Additionally, the following example demonstrates how you can add custom styles for a message action title.

```tsx
<Channel
  messageActions={({ copyMessage, deleteMessage, editMessage, isMyMessage }) =>
    isMyMessage
      ? [
          copyMessage,
          editMessage,
          {
            ...deleteMessage,
            titleStyle: {
              color: "red",
              fontWeight: "bold",
            },
          },
        ]
      : [copyMessage]
  }
>
  {/** MessageList and MessageInput component here */}
</Channel>
```

## How to add a custom message action

- Add a new custom action - "Mute User"
- Show "Mute User" action only for messages from other user.

```tsx
import {
  messageActions as defaultMessageActions,
  Mute as MuteIcon,
} from "stream-chat-react-native";

<Channel
  channel={channel}
  messageActions={(param) => {
    const { isMyMessage, ownCapabilities, dismissOverlay } = param;
    const actions = defaultMessageActions({ ...param });

    if (!isMyMessage) {
      const isMuted = (client.mutedUsers || []).some(
        (mute) =>
          mute.user.id === client.userID && mute.target.id === message.user?.id,
      );

      actions.push({
        action: async () => {
          dismissOverlay();
          if (message.user?.id) {
            if (isMuted) {
              await client.unmuteUser(message.user.id);
            } else {
              await client.muteUser(message.user.id);
            }
          }
        },
        actionType: "custom-mute-user",
        icon: <MuteIcon />,
        title: isMuted ? t("Custom Unmute User") : t("Custom Mute User"),
      });
    }

    return actions;
  }}
>
  {/** MessageList and MessageInput component here */}
</Channel>;
```

## How to customize message action UI

`Channel` accepts `MessageActionList` and `MessageActionListItem`. They serve different purposes:

- `MessageActionList` - Full control over the action list and its styles.
- `MessageActionListItem` - Customize a single action item.

### Customize a Message Action List

Example `MessageActionList`:

```tsx
import { Alert } from "react-native";
import {
  Channel,
  MessageActionListItem,
  useMessageContext,
} from "stream-chat-react-native";

const CustomMessageActionList = () => {
  const { dismissOverlay } = useMessageContext();
  const messageActions = [
    {
      action: () => {
        Alert.alert("Edit Message action called.");
        dismissOverlay();
      },
      actionType: "editMessage",
      title: "Edit message",
    },
    {
      action: () => {
        Alert.alert("Delete message action");
        dismissOverlay();
      },
      actionType: "deleteMessage",
      title: "Delete Message",
    },
  ];
  return (
    <View style={{ backgroundColor: "white" }}>
      {messageActions.map(({ actionType, ...rest }) => (
        <MessageActionListItem
          actionType={actionType}
          key={actionType}
          {...rest}
        />
      ))}
    </View>
  );
};

<Channel MessageActionList={CustomMessageActionList}>
  {/* Underlying MessageList and MessageInput components */}
</Channel>;
```

`MessageActionList` is just a prop that accepts your component. You define content, styles, and logic.

### Customize Message Action list item

To customize `pinMessage` and `muteUser`, check `actionType` and return your own component.

The types of actions which are available by default are as follows:

- `blockUser`
- `copyMessage`
- `deleteMessage`
- `deleteForMeMessage`
- `editMessage`
- `flagMessage`
- `markUnread`
- `muteUser`
- `pinMessage`
- `selectReaction`
- `reply`
- `retry`
- `quotedReply`
- `threadReply`
- `unpinMessage`

If no custom condition matches, return the default `MessageActionListItem`.

You can use these props to provide your own component.

Example `MessageActionListItem` customization:

```tsx
import { Pressable, Text } from "react-native";
import {
  Channel,
  MessageActionListItem,
  useMessageActionAnimation,
} from "stream-chat-react-native";

const CustomMessageActionListItem = ({
  action,
  actionType,
  ...rest
}: MessageActionListItemProps) => {
  if (actionType === "pinMessage") {
    return (
      <Pressable onPress={action}>
        <Text>{actionType}</Text>
      </Pressable>
    );
  } else if (actionType === "muteUser") {
    return (
      <Pressable onPress={action}>
        <Text>{actionType}</Text>
      </Pressable>
    );
  } else {
    return (
      <MessageActionListItem
        action={action}
        actionType={actionType}
        {...rest}
      />
    );
  }
};

<Channel MessageActionListItem={CustomMessageActionListItem}>
  {/* Underlying MessageList and MessageInput components */}
</Channel>;
```

Please continue reading further to see different use cases.

## How to intercept a message action

To add analytics tracking, use these handler props (called before the default handlers):

<admonition type="note">

Please note that these intercepts will neither change the standard functions nor block them.

</admonition>

- `handleBan`
- `handleCopy`
- `handleDelete`
- `handleDeleteForMe`
- `handleEdit`
- `handleFlag`
- `handleMute`
- `handleReaction`
- `handleReply`
- `handleRetry`
- `handleThreadReply`

Example: track "Copy Message":

```tsx
<Channel handleCopy={() => trackCopyAction()} />
```

## How to disable a message action

To disable an action, return `null` for that `actionType` in `MessageActionListItem`:

```tsx
import {
  Channel,
  MessageActionListItem,
  useMessageActionAnimation,
} from "stream-chat-react-native";

const CustomMessageActionListItem = ({ action, actionType, ...rest }) => {
  if (actionType === "pinMessage") {
    return null;
  } else {
    return (
      <MessageActionListItem
        action={action}
        actionType={actionType}
        {...rest}
      />
    );
  }
};

<Channel MessageActionListItem={CustomMessageActionListItem}>
  {/* Underlying MessageList and MessageInput components */}
</Channel>;
```


---

This page was last updated at 2026-04-17T17:33:45.119Z.

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react-native/v8/guides/customize-message-actions/](https://getstream.io/chat/docs/sdk/react-native/v8/guides/customize-message-actions/).