import { useDeleteHandler, useMessageContext } from "stream-chat-react";
const CustomMessage = () => {
const { message } = useMessageContext();
const handleDelete = useDeleteHandler(message);
const onDelete = async () => {
try {
await handleDelete();
} catch {
// The SDK already shows its default delete error notification.
}
};
return <button onClick={onDelete}>Delete {message.id}</button>;
};This is beta documentation for Stream Chat React SDK v14. For the latest stable version, see the latest version (v13)
.
Message Hooks
The React Chat SDK exports hooks that help you build custom message UI without re-implementing channel actions manually.
Best Practices
- Prefer these hooks over re-creating message action logic yourself.
- Keep hook handlers attached to explicit user interactions.
- Use
useMessageContext()as the source of truth for the current message. - Test permission-dependent hooks with realistic roles and capabilities.
- Use the message composer for edit flows instead of maintaining local message edit state.
Hooks
Action and moderation hooks
useActionHandlerhandles slash-command style message actions.useDeleteHandlerdeletes a message.useFlagHandlerflags a message.useMarkUnreadHandlermarks a message and following messages unread.useMuteHandlermutes the message sender.usePinHandlerhandles message pinning.useRetryHandlerretries a failed message send.
Thread, reaction, and mention hooks
useOpenThreadHandleropens a thread for the current message.useReactionHandleradds or removes a reaction.useReactionsFetcherloads message reactions.useMentionsHandlerprovides click and hover handlers for mentions.
User helper hooks
useUserHandlerresolves avatar/name click and hover handlers.useUserRolecomputes permission-dependent message capabilities.
Examples
useDeleteHandler
For unsent or network-failed messages, useDeleteHandler() removes the message locally. For server-side delete failures, it now rethrows after the SDK shows its default error notification.
useMarkUnreadHandler
import {
useMarkUnreadHandler,
useMessageContext,
useUserRole,
} from "stream-chat-react";
const MarkUnreadButton = () => {
const { message } = useMessageContext();
const { canMarkUnread } = useUserRole(message);
const handleMarkUnread = useMarkUnreadHandler(message);
if (!canMarkUnread) return null;
return <button onClick={handleMarkUnread}>Mark unread</button>;
};markUnread is only available for foreign messages when the connected user also has the required read-events capability.
useReactionHandler
import { useMessageContext, useReactionHandler } from "stream-chat-react";
const CustomReactionButtons = () => {
const { message } = useMessageContext();
const handleReaction = useReactionHandler(message);
return (
<>
<button onClick={(event) => handleReaction("love", event)}>Love</button>
<button onClick={(event) => handleReaction("fire", event)}>Fire</button>
</>
);
};useRetryHandler
import { useMessageContext, useRetryHandler } from "stream-chat-react";
const RetryButton = () => {
const { message } = useMessageContext();
const handleRetry = useRetryHandler(message);
return <button onClick={handleRetry}>Retry</button>;
};useUserRole
import { useMessageContext, useUserRole } from "stream-chat-react";
const MessageCapabilities = () => {
const { message } = useMessageContext();
const { canDelete, canEdit, canReply } = useUserRole(message);
return (
<div>
{String(canEdit)} / {String(canDelete)} / {String(canReply)}
</div>
);
};If your message UI needs editing behavior, initialize the current message in the message composer rather than relying on a dedicated message edit hook.