# Message Actions

## The Problem(s)

Message actions are handled by `MessageOptions` and its children (`MessageActions`, `MessageActionsBox`). Actions are buttons in a dropdown tied to a specific message or its author.

![MessageOptions structure](@chat-sdk/react/v13/_assets/message-options-structure.png)

Customizing action buttons (text, translations, etc.) is hard with the current components. `CustomMessageActionsList` lets you override dropdown buttons via `ComponentContext`, but it doesn’t control when or how options buttons (dropdown, reply, react) appear.

## The New Approach

To address these gaps, the experimental `MessageActions` component allows:

1. defining the button components rendered in the dropdown
2. placing actions in the dropdown or as quick actions
3. filtering which actions appear in each place

## Best Practices

- Use the experimental API only when default message actions are insufficient.
- Keep custom action components stable to avoid re-render churn.
- Always filter actions based on permissions and roles.
- Prefer merging with the default action set for compatibility.
- Re-validate UI after SDK upgrades due to experimental changes.

<admonition type="note">
This feature is experimental and may change. In a future major version, `MessageOptions` might no longer wrap `MessageActions`, which would change the markup. This is because `MessageActions` distinguishes between `dropdown` and `quick` placement.
</admonition>

## The Customization Process

1. Define action components with `quick` or `dropdown` placement.
2. Decide whether to merge with the default action set.
3. Define a filter (or use the default) based on permissions and app logic.

The customization example follows:

```tsx
import { useMemo } from "react";
import { Channel } from "stream-chat-react";
import {
  MessageActions,
  defaultMessageActionSet,
  DefaultDropdownActionButton,
} from "stream-chat-react/experimental";

import { useCustomMessageActionRules } from "./useCustomMessageActionRules";

const CustomMessageActions = () => {
  const customRules = useCustomMessageActionRules(); // your implementation

  const customMessageActionSet = useMemo(() => {
    return [
      // reuse the default set if you need
      ...defaultMessageActionSet,
      {
        type: "myCustomTypeDropdown",
        placement: "dropdown",
        // we recommend defining components outside the scope of
        // the CustomMessageActions component to keep them stable
        Component: () => (
          <DefaultDropdownActionButton>🚀 Custom</DefaultDropdownActionButton>
        ),
      },
      {
        type: "myCustomTypeQuick",
        placement: "quick",
        Component: () => <button>a</button>,
      },
    ].filter(
      // apply custom filter with access to values from contexts and hooks
      (action) => {
        return !customRules.disallow.includes(action.type);
      },
    );
  }, [customRules]);

  return (
    <MessageActions
      // though not recommended, it's possible to completely disable the default filter
      disableBaseMessageActionSetFilter
      messageActionSet={customMessageActionSet}
    />
  );
};

<Channel MessageActions={CustomMessageActions}>...</Channel>;
```

![image](@chat-sdk/react/v13/_assets/custom-message-actions-experimental.png)


---

This page was last updated at 2026-04-21T07:55:48.036Z.

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