diff --git a/src/app/features/room/MessageOptionsMenu.tsx b/src/app/features/room/MessageOptionsMenu.tsx
new file mode 100644
index 00000000..43e5b751
--- /dev/null
+++ b/src/app/features/room/MessageOptionsMenu.tsx
@@ -0,0 +1,273 @@
+import { Box, Icon, IconButton, Icons, Line, Menu, MenuItem, PopOut, RectCords, Text } from 'folds';
+import React, { MouseEventHandler, useEffect, useState } from 'react';
+
+import FocusTrap from 'focus-trap-react';
+import { EmojiBoard } from '../../components/emoji-board';
+import { stopPropagation } from '../../utils/keyboard';
+import * as css from './message/styles.css';
+
+import {
+ MessageAllReactionItem,
+ MessageCopyLinkItem,
+ MessageDeleteItem,
+ MessagePinItem,
+ MessageQuickReactions,
+ MessageReadReceiptItem,
+ MessageReportItem,
+ MessageSourceCodeItem,
+} from './message/Message';
+
+export function MessageDropdownMenu({
+ mEvent,
+ room,
+ mx,
+ relations,
+ eventId,
+ canSendReaction,
+ canEdit,
+ canDelete,
+ canPinEvent,
+ hideReadReceipts,
+ onReactionToggle,
+ onReplyClick,
+ onEditId,
+ handleAddReactions,
+ closeMenu,
+}) {
+ return (
+
+ );
+}
+
+export function MessageOptionsMenu({
+ mEvent,
+ room,
+ mx,
+ relations,
+ imagePackRooms,
+ canSendReaction,
+ canEdit,
+ canDelete,
+ canPinEvent,
+ hideReadReceipts,
+ onReactionToggle,
+ onReplyClick,
+ onEditId,
+ onActiveStateChange,
+}) {
+ const [menuAnchor, setMenuAnchor] = useState();
+ const [emojiBoardAnchor, setEmojiBoardAnchor] = useState();
+
+ useEffect(() => {
+ onActiveStateChange?.(!!menuAnchor || !!emojiBoardAnchor);
+ }, [emojiBoardAnchor, menuAnchor, onActiveStateChange]);
+
+ const eventId = mEvent.getId();
+ if (!eventId) return null;
+
+ const closeMenu = () => {
+ setMenuAnchor(undefined);
+ };
+
+ const handleOpenMenu: MouseEventHandler = (evt) => {
+ const target = evt.currentTarget.parentElement?.parentElement ?? evt.currentTarget;
+ setMenuAnchor(target.getBoundingClientRect());
+ };
+
+ const handleOpenEmojiBoard: MouseEventHandler = (evt) => {
+ const target = evt.currentTarget.parentElement?.parentElement ?? evt.currentTarget;
+ setEmojiBoardAnchor(target.getBoundingClientRect());
+ };
+
+ const handleAddReactions: MouseEventHandler = () => {
+ const rect = menuAnchor;
+ closeMenu();
+ // Use a timeout to allow the first menu to close before opening the next
+ setTimeout(() => {
+ setEmojiBoardAnchor(rect);
+ }, 100);
+ };
+ return (
+
+
+
+ );
+}