import {
type ContextMenuItemProps,
Channel,
MessageActions,
WithComponents,
defaultMessageActionSet,
useMessageContext,
} from "stream-chat-react";
const YellAction = ({ closeMenu }: ContextMenuItemProps) => {
const { message } = useMessageContext("YellAction");
return (
<button
className="str-chat__message-actions-list-item-button"
onClick={() => {
window.alert(`Yell action clicked on message: ${message.id}!`);
closeMenu();
}}
>
Yell
</button>
);
};
const CustomMessageActions = () => (
<MessageActions
messageActionSet={[
...defaultMessageActionSet,
{
Component: YellAction,
placement: "dropdown",
type: "yell",
},
]}
/>
);
export const WrappedChannel = ({ children }) => (
<WithComponents overrides={{ MessageActions: CustomMessageActions }}>
<Channel>{children}</Channel>
</WithComponents>
);This is beta documentation for Stream Chat React SDK v14. For the latest stable version, see the latest version (v13)
.
Message Actions
This example shows how to add custom actions to the SDK message action menu.
Best Practices
- Start from
defaultMessageActionSetunless you need a fully custom action surface. - Keep custom actions small and read message state from hooks like
useMessageContext(). - Register custom actions with
WithComponentsso the same override works inMessageList,Thread, andVirtualizedMessageList. - Keep action handlers fast and idempotent.
- Re-check custom actions in both channel and thread views because the SDK filters some actions differently across contexts.
Built-in Actions
The default action set can include these action types:
deleteeditflagmarkUnreadmutepinquotereactremindMereplyresendsaveForLater
Add A Custom Dropdown Action
Use defaultMessageActionSet as a base and append your own dropdown item.
Add A Quick Action
Quick actions render inline next to the message instead of inside the dropdown menu.
import {
Channel,
MessageActions,
WithComponents,
defaultMessageActionSet,
useMessageContext,
} from "stream-chat-react";
const CopyIdAction = () => {
const { message } = useMessageContext("CopyIdAction");
return (
<button onClick={() => navigator.clipboard.writeText(message.id)}>
Copy ID
</button>
);
};
const CustomMessageActions = () => (
<MessageActions
messageActionSet={[
...defaultMessageActionSet,
{
Component: CopyIdAction,
placement: "quick",
type: "copy-id",
},
]}
/>
);
export const WrappedChannel = ({ children }) => (
<WithComponents overrides={{ MessageActions: CustomMessageActions }}>
<Channel>{children}</Channel>
</WithComponents>
);Filter The Defaults
The SDK filters the default action set based on permissions, message state, and thread context. In most cases, keep that filtering enabled and only remove or add items intentionally.
import { MessageActions, defaultMessageActionSet } from "stream-chat-react";
const CustomMessageActions = () => (
<MessageActions
messageActionSet={defaultMessageActionSet.filter(
({ type }) => type !== "markUnread",
)}
/>
);If you pass disableBaseMessageActionSetFilter, the SDK stops applying that default permission/state filtering. Only do that if your custom actions already enforce the same constraints.