diff --git a/web/chat/composed-message.react.js b/web/chat/composed-message.react.js
--- a/web/chat/composed-message.react.js
+++ b/web/chat/composed-message.react.js
@@ -20,7 +20,8 @@
 import UserAvatar from '../components/user-avatar.react.js';
 import { type InputState, InputStateContext } from '../input/input-state.js';
 import { shouldRenderAvatars } from '../utils/avatar-utils.js';
-import { tooltipPositions, useMessageTooltip } from '../utils/tooltip-utils.js';
+import { useMessageTooltip } from '../utils/tooltip-action-utils.js';
+import { tooltipPositions } from '../utils/tooltip-utils.js';
 
 const availableTooltipPositionsForViewerMessage = [
   tooltipPositions.LEFT,
diff --git a/web/chat/robotext-message.react.js b/web/chat/robotext-message.react.js
--- a/web/chat/robotext-message.react.js
+++ b/web/chat/robotext-message.react.js
@@ -19,7 +19,8 @@
 import { linkRules } from '../markdown/rules.react.js';
 import { updateNavInfoActionType } from '../redux/action-types.js';
 import { useSelector } from '../redux/redux-utils.js';
-import { tooltipPositions, useMessageTooltip } from '../utils/tooltip-utils.js';
+import { useMessageTooltip } from '../utils/tooltip-action-utils.js';
+import { tooltipPositions } from '../utils/tooltip-utils.js';
 
 const availableTooltipPositionsForRobotext = [
   tooltipPositions.LEFT,
diff --git a/web/components/pinned-message.css b/web/components/pinned-message.css
new file mode 100644
--- /dev/null
+++ b/web/components/pinned-message.css
@@ -0,0 +1,28 @@
+.messageContainer {
+    overflow-y: scroll;
+    border: 1px solid var(--pin-message-modal-border-color);
+    border-radius: 7px;
+    max-height: 400px;
+    margin: 16px 32px;
+}
+
+.messageDate {
+    color: var(--chat-timestamp-color);
+    font-size: var(--xs-font-12);
+    padding: 0px 0px 6px 0px;
+    line-height: var(--line-height-text);
+    text-align: left;
+    margin-left: 16px;
+}
+
+.creator {
+    font-size: small;
+    color: var(--shades-white-60);
+    font-size: var(--s-font-14);
+    padding: 4px 24px;
+    text-align: left;
+}
+
+.messageContent {
+    margin-bottom: 1px;
+}
diff --git a/web/components/pinned-message.react.js b/web/components/pinned-message.react.js
new file mode 100644
--- /dev/null
+++ b/web/components/pinned-message.react.js
@@ -0,0 +1,57 @@
+// @flow
+
+import * as React from 'react';
+
+import { useStringForUser } from 'lib/hooks/ens-cache.js';
+import type { ChatMessageInfoItem } from 'lib/selectors/chat-selectors.js';
+import type { ThreadInfo } from 'lib/types/thread-types.js';
+import { longAbsoluteDate } from 'lib/utils/date-utils.js';
+
+import css from './pinned-message.css';
+import { MessageListContext } from '../chat/message-list-types.js';
+import Message from '../chat/message.react.js';
+import { useTextMessageRulesFunc } from '../markdown/rules.react.js';
+
+type PinnedMessageProps = {
+  +item: ChatMessageInfoItem,
+  +threadInfo: ThreadInfo,
+};
+
+function PinnedMessage(props: PinnedMessageProps): React.Node {
+  const { item, threadInfo } = props;
+
+  const getTextMessageMarkdownRules = useTextMessageRulesFunc(threadInfo);
+  const messageListContext = React.useMemo(() => {
+    if (!getTextMessageMarkdownRules) {
+      return undefined;
+    }
+    return { getTextMessageMarkdownRules };
+  }, [getTextMessageMarkdownRules]);
+
+  const shouldShowUsername = !item.startsConversation && !item.startsCluster;
+  const username = useStringForUser(
+    shouldShowUsername ? item.messageInfo.creator : null,
+  );
+
+  return (
+    <div className={css.messageContainer}>
+      <div>
+        <div className={css.creator}>{username}</div>
+        <div className={css.messageContent}>
+          <MessageListContext.Provider value={messageListContext}>
+            <Message
+              item={item}
+              threadInfo={threadInfo}
+              key={item.messageInfo.id}
+            />
+          </MessageListContext.Provider>
+        </div>
+        <div className={css.messageDate}>
+          {longAbsoluteDate(item.messageInfo.time)}
+        </div>
+      </div>
+    </div>
+  );
+}
+
+export default PinnedMessage;
diff --git a/web/modals/chat/toggle-pin-modal.css b/web/modals/chat/toggle-pin-modal.css
--- a/web/modals/chat/toggle-pin-modal.css
+++ b/web/modals/chat/toggle-pin-modal.css
@@ -0,0 +1,30 @@
+.confirmationText {
+    color: var(--pin-message-information-text-color);
+    padding: 16px 32px 0 32px;
+    font-size: small;
+}
+
+.buttonContainer {
+    width: 100%;
+    display: flex;
+    flex-direction: column;
+    align-self: center;
+    align-items: stretch;
+    margin-bottom: 16px;
+}
+
+.togglePinButton {
+    margin: 0 32px 0 32px;
+}
+
+.cancelButton {
+    color: white;
+    display: flex;
+    justify-content: center;
+    margin-top: 16px;
+}
+
+.cancelButton:hover {
+    cursor: pointer;
+    text-decoration: underline;
+}
diff --git a/web/modals/chat/toggle-pin-modal.react.js b/web/modals/chat/toggle-pin-modal.react.js
--- a/web/modals/chat/toggle-pin-modal.react.js
+++ b/web/modals/chat/toggle-pin-modal.react.js
@@ -1,18 +1,129 @@
 // @flow
 
+import invariant from 'invariant';
 import * as React from 'react';
 
+import {
+  toggleMessagePin,
+  toggleMessagePinActionTypes,
+} from 'lib/actions/thread-actions.js';
+import { useModalContext } from 'lib/components/modal-provider.react.js';
 import type { ChatMessageInfoItem } from 'lib/selectors/chat-selectors.js';
 import type { ThreadInfo } from 'lib/types/thread-types.js';
+import {
+  useServerCall,
+  useDispatchActionPromise,
+} from 'lib/utils/action-utils.js';
+
+import css from './toggle-pin-modal.css';
+import Button, { buttonThemes } from '../../components/button.react.js';
+import PinnedMessage from '../../components/pinned-message.react.js';
+import Modal from '../modal.react.js';
 
 type TogglePinModalProps = {
   +item: ChatMessageInfoItem,
   +threadInfo: ThreadInfo,
 };
 
-// eslint-disable-next-line no-unused-vars
 function TogglePinModal(props: TogglePinModalProps): React.Node {
-  return <></>;
+  const { item, threadInfo } = props;
+  const { messageInfo, isPinned } = item;
+  const { popModal } = useModalContext();
+
+  const callToggleMessagePin = useServerCall(toggleMessagePin);
+  const dispatchActionPromise = useDispatchActionPromise();
+
+  const modalInfo = React.useMemo(() => {
+    if (isPinned) {
+      return {
+        name: 'Remove Pinned Message',
+        action: 'unpin',
+        confirmationText:
+          'Are you sure you want to remove this pinned message?',
+        buttonText: 'Remove Pinned Message',
+        buttonColor: buttonThemes.danger,
+      };
+    }
+
+    return {
+      name: 'Pin Message',
+      action: 'pin',
+      confirmationText: `You may pin this message to the channel 
+        you are currently viewing. To unpin a message, select the pinned 
+        messages icon in the channel.`,
+      buttonText: 'Pin Message',
+      buttonColor: buttonThemes.standard,
+    };
+  }, [isPinned]);
+
+  // We want to remove inline engagement (threadCreatedFromMessage / reactions)
+  // and the message header (startsConversation). We also want to set isViewer
+  // to false so that the message is left-aligned and uncolored.
+  const modifiedItem = React.useMemo(() => {
+    if (item.messageInfoType !== 'composable') {
+      return item;
+    }
+
+    return {
+      ...item,
+      threadCreatedFromMessage: undefined,
+      reactions: {},
+      startsConversation: false,
+      messageInfo: {
+        ...item.messageInfo,
+        creator: {
+          ...item.messageInfo.creator,
+          isViewer: false,
+        },
+      },
+    };
+  }, [item]);
+
+  const onClick = React.useCallback(() => {
+    const createToggleMessagePinPromise = async () => {
+      invariant(messageInfo.id, 'messageInfo.id should be defined');
+      const result = await callToggleMessagePin({
+        messageID: messageInfo.id,
+        action: modalInfo.action,
+      });
+      return {
+        newMessageInfos: result.newMessageInfos,
+        threadID: result.threadID,
+      };
+    };
+
+    dispatchActionPromise(
+      toggleMessagePinActionTypes,
+      createToggleMessagePinPromise(),
+    );
+    popModal();
+  }, [
+    modalInfo,
+    callToggleMessagePin,
+    dispatchActionPromise,
+    messageInfo.id,
+    popModal,
+  ]);
+
+  return (
+    <Modal name={modalInfo.name} onClose={popModal} size="large">
+      <div className={css.confirmationText}>{modalInfo.confirmationText}</div>
+      <PinnedMessage item={modifiedItem} threadInfo={threadInfo} />
+      <div className={css.buttonContainer}>
+        <Button
+          variant="filled"
+          className={css.togglePinButton}
+          buttonColor={modalInfo.buttonColor}
+          onClick={onClick}
+        >
+          {modalInfo.buttonText}
+        </Button>
+        <div className={css.cancelButton} onClick={popModal}>
+          Cancel
+        </div>
+      </div>
+    </Modal>
+  );
 }
 
 export default TogglePinModal;
diff --git a/web/theme.css b/web/theme.css
--- a/web/theme.css
+++ b/web/theme.css
@@ -212,4 +212,6 @@
   --topbar-button-fg: var(--shades-white-60);
   --message-label-color: var(--shades-black-60);
   --topbar-lines: rgba(255, 255, 255, 0.08);
+  --pin-message-information-text-color: var(--shades-white-60);
+  --pin-message-modal-border-color: var(--shades-black-80);
 }
diff --git a/web/utils/tooltip-utils.js b/web/utils/tooltip-action-utils.js
copy from web/utils/tooltip-utils.js
copy to web/utils/tooltip-action-utils.js
--- a/web/utils/tooltip-utils.js
+++ b/web/utils/tooltip-action-utils.js
@@ -20,12 +20,14 @@
 import { threadPermissions } from 'lib/types/thread-types.js';
 import { longAbsoluteDate } from 'lib/utils/date-utils.js';
 
-import { getAppContainerPositionInfo } from './window-utils.js';
 import {
-  tooltipButtonStyle,
-  tooltipLabelStyle,
-  tooltipStyle,
-} from '../chat/chat-constants.js';
+  type MessageTooltipAction,
+  findTooltipPosition,
+  getMessageActionTooltipStyle,
+  calculateTooltipSize,
+  type TooltipSize,
+  type TooltipPosition,
+} from './tooltip-utils.js';
 import MessageTooltip from '../chat/message-tooltip.react.js';
 import type { PositionInfo } from '../chat/position-types.js';
 import { useTooltipContext } from '../chat/tooltip-provider.js';
@@ -36,310 +38,6 @@
   useOnClickPendingSidebar,
   useOnClickThread,
 } from '../selectors/thread-selectors.js';
-import { calculateMaxTextWidth } from '../utils/text-utils.js';
-
-export const tooltipPositions = Object.freeze({
-  LEFT: 'left',
-  RIGHT: 'right',
-  LEFT_BOTTOM: 'left-bottom',
-  RIGHT_BOTTOM: 'right-bottom',
-  LEFT_TOP: 'left-top',
-  RIGHT_TOP: 'right-top',
-  TOP: 'top',
-  BOTTOM: 'bottom',
-});
-
-export type TooltipSize = {
-  +height: number,
-  +width: number,
-};
-
-export type TooltipPositionStyle = {
-  +anchorPoint: {
-    +x: number,
-    +y: number,
-  },
-  +verticalPosition: 'top' | 'bottom',
-  +horizontalPosition: 'left' | 'right',
-  +alignment: 'left' | 'center' | 'right',
-};
-
-export type TooltipPosition = $Values<typeof tooltipPositions>;
-
-export type MessageTooltipAction = {
-  +label: string,
-  +onClick: (SyntheticEvent<HTMLDivElement>) => mixed,
-  +actionButtonContent: React.Node,
-};
-
-const font =
-  '14px "Inter", -apple-system, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", ' +
-  '"Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", ui-sans-serif';
-
-type FindTooltipPositionArgs = {
-  +sourcePositionInfo: PositionInfo,
-  +tooltipSize: TooltipSize,
-  +availablePositions: $ReadOnlyArray<TooltipPosition>,
-  +defaultPosition: TooltipPosition,
-  +preventDisplayingBelowSource?: boolean,
-};
-
-function findTooltipPosition({
-  sourcePositionInfo,
-  tooltipSize,
-  availablePositions,
-  defaultPosition,
-  preventDisplayingBelowSource,
-}: FindTooltipPositionArgs): TooltipPosition {
-  const appContainerPositionInfo = getAppContainerPositionInfo();
-
-  if (!appContainerPositionInfo) {
-    return defaultPosition;
-  }
-
-  const pointingTo = sourcePositionInfo;
-  const {
-    top: containerTop,
-    left: containerLeft,
-    right: containerRight,
-    bottom: containerBottom,
-  } = appContainerPositionInfo;
-
-  const tooltipWidth = tooltipSize.width;
-  const tooltipHeight = tooltipSize.height;
-
-  const canBeDisplayedOnLeft = containerLeft + tooltipWidth <= pointingTo.left;
-  const canBeDisplayedOnRight =
-    tooltipWidth + pointingTo.right <= containerRight;
-
-  const willCoverSidebarOnTopSideways =
-    preventDisplayingBelowSource &&
-    pointingTo.top + tooltipHeight > pointingTo.bottom;
-
-  const canBeDisplayedOnTopSideways =
-    pointingTo.top >= containerTop &&
-    pointingTo.top + tooltipHeight <= containerBottom &&
-    !willCoverSidebarOnTopSideways;
-
-  const canBeDisplayedOnBottomSideways =
-    pointingTo.bottom <= containerBottom &&
-    pointingTo.bottom - tooltipHeight >= containerTop;
-
-  const verticalCenterOfPointingTo = pointingTo.top + pointingTo.height / 2;
-  const horizontalCenterOfPointingTo = pointingTo.left + pointingTo.width / 2;
-
-  const willCoverSidebarInTheMiddleSideways =
-    preventDisplayingBelowSource &&
-    verticalCenterOfPointingTo + tooltipHeight / 2 > pointingTo.bottom;
-
-  const canBeDisplayedInTheMiddleSideways =
-    verticalCenterOfPointingTo - tooltipHeight / 2 >= containerTop &&
-    verticalCenterOfPointingTo + tooltipHeight / 2 <= containerBottom &&
-    !willCoverSidebarInTheMiddleSideways;
-
-  const canBeDisplayedOnTop =
-    pointingTo.top - tooltipHeight >= containerTop &&
-    horizontalCenterOfPointingTo - tooltipWidth / 2 >= containerLeft &&
-    horizontalCenterOfPointingTo + tooltipWidth / 2 <= containerRight;
-
-  const canBeDisplayedOnBottom =
-    pointingTo.bottom + tooltipHeight <= containerBottom &&
-    horizontalCenterOfPointingTo - tooltipWidth / 2 >= containerLeft &&
-    horizontalCenterOfPointingTo + tooltipWidth / 2 <= containerRight &&
-    !preventDisplayingBelowSource;
-
-  for (const tooltipPosition of availablePositions) {
-    if (
-      tooltipPosition === tooltipPositions.RIGHT &&
-      canBeDisplayedOnRight &&
-      canBeDisplayedInTheMiddleSideways
-    ) {
-      return tooltipPosition;
-    } else if (
-      tooltipPosition === tooltipPositions.RIGHT_BOTTOM &&
-      canBeDisplayedOnRight &&
-      canBeDisplayedOnBottomSideways
-    ) {
-      return tooltipPosition;
-    } else if (
-      tooltipPosition === tooltipPositions.LEFT &&
-      canBeDisplayedOnLeft &&
-      canBeDisplayedInTheMiddleSideways
-    ) {
-      return tooltipPosition;
-    } else if (
-      tooltipPosition === tooltipPositions.LEFT_BOTTOM &&
-      canBeDisplayedOnLeft &&
-      canBeDisplayedOnBottomSideways
-    ) {
-      return tooltipPosition;
-    } else if (
-      tooltipPosition === tooltipPositions.LEFT_TOP &&
-      canBeDisplayedOnLeft &&
-      canBeDisplayedOnTopSideways
-    ) {
-      return tooltipPosition;
-    } else if (
-      tooltipPosition === tooltipPositions.RIGHT_TOP &&
-      canBeDisplayedOnRight &&
-      canBeDisplayedOnTopSideways
-    ) {
-      return tooltipPosition;
-    } else if (
-      tooltipPosition === tooltipPositions.TOP &&
-      canBeDisplayedOnTop
-    ) {
-      return tooltipPosition;
-    } else if (
-      tooltipPosition === tooltipPositions.BOTTOM &&
-      canBeDisplayedOnBottom
-    ) {
-      return tooltipPosition;
-    }
-  }
-  return defaultPosition;
-}
-
-type GetMessageActionTooltipStyleParams = {
-  +sourcePositionInfo: PositionInfo,
-  +tooltipSize: TooltipSize,
-  +tooltipPosition: TooltipPosition,
-};
-
-function getMessageActionTooltipStyle({
-  sourcePositionInfo,
-  tooltipSize,
-  tooltipPosition,
-}: GetMessageActionTooltipStyleParams): TooltipPositionStyle {
-  if (tooltipPosition === tooltipPositions.RIGHT_TOP) {
-    return {
-      anchorPoint: {
-        x: sourcePositionInfo.right,
-        y: sourcePositionInfo.top,
-      },
-      horizontalPosition: 'right',
-      verticalPosition: 'bottom',
-      alignment: 'left',
-    };
-  } else if (tooltipPosition === tooltipPositions.LEFT_TOP) {
-    return {
-      anchorPoint: {
-        x: sourcePositionInfo.left,
-        y: sourcePositionInfo.top,
-      },
-      horizontalPosition: 'left',
-      verticalPosition: 'bottom',
-      alignment: 'right',
-    };
-  } else if (tooltipPosition === tooltipPositions.RIGHT_BOTTOM) {
-    return {
-      anchorPoint: {
-        x: sourcePositionInfo.right,
-        y: sourcePositionInfo.bottom,
-      },
-      horizontalPosition: 'right',
-      verticalPosition: 'top',
-      alignment: 'left',
-    };
-  } else if (tooltipPosition === tooltipPositions.LEFT_BOTTOM) {
-    return {
-      anchorPoint: {
-        x: sourcePositionInfo.left,
-        y: sourcePositionInfo.bottom,
-      },
-      horizontalPosition: 'left',
-      verticalPosition: 'top',
-      alignment: 'right',
-    };
-  } else if (tooltipPosition === tooltipPositions.LEFT) {
-    return {
-      anchorPoint: {
-        x: sourcePositionInfo.left,
-        y:
-          sourcePositionInfo.top +
-          sourcePositionInfo.height / 2 -
-          tooltipSize.height / 2,
-      },
-      horizontalPosition: 'left',
-      verticalPosition: 'bottom',
-      alignment: 'right',
-    };
-  } else if (tooltipPosition === tooltipPositions.RIGHT) {
-    return {
-      anchorPoint: {
-        x: sourcePositionInfo.right,
-        y:
-          sourcePositionInfo.top +
-          sourcePositionInfo.height / 2 -
-          tooltipSize.height / 2,
-      },
-      horizontalPosition: 'right',
-      verticalPosition: 'bottom',
-      alignment: 'left',
-    };
-  } else if (tooltipPosition === tooltipPositions.TOP) {
-    return {
-      anchorPoint: {
-        x:
-          sourcePositionInfo.left +
-          sourcePositionInfo.width / 2 -
-          tooltipSize.width / 2,
-        y: sourcePositionInfo.top,
-      },
-      horizontalPosition: 'right',
-      verticalPosition: 'top',
-      alignment: 'center',
-    };
-  } else if (tooltipPosition === tooltipPositions.BOTTOM) {
-    return {
-      anchorPoint: {
-        x:
-          sourcePositionInfo.left +
-          sourcePositionInfo.width / 2 -
-          tooltipSize.width / 2,
-        y: sourcePositionInfo.bottom,
-      },
-      horizontalPosition: 'right',
-      verticalPosition: 'bottom',
-      alignment: 'center',
-    };
-  }
-  invariant(false, `Unexpected tooltip position value: ${tooltipPosition}`);
-}
-
-type CalculateTooltipSizeArgs = {
-  +tooltipLabels: $ReadOnlyArray<string>,
-  +timestamp: string,
-};
-
-function calculateTooltipSize({
-  tooltipLabels,
-  timestamp,
-}: CalculateTooltipSizeArgs): {
-  +width: number,
-  +height: number,
-} {
-  const textWidth =
-    calculateMaxTextWidth([...tooltipLabels, timestamp], font) +
-    2 * tooltipLabelStyle.padding;
-  const buttonsWidth =
-    tooltipLabels.length *
-    (tooltipButtonStyle.width +
-      tooltipButtonStyle.paddingLeft +
-      tooltipButtonStyle.paddingRight);
-  const width =
-    Math.max(textWidth, buttonsWidth) +
-    tooltipStyle.paddingLeft +
-    tooltipStyle.paddingRight;
-  const height =
-    (tooltipLabelStyle.height + 2 * tooltipLabelStyle.padding) * 2 +
-    tooltipStyle.rowGap * 2 +
-    tooltipButtonStyle.height;
-  return {
-    width,
-    height,
-  };
-}
 
 function useMessageTooltipSidebarAction(
   item: ChatMessageInfoItem,
@@ -494,6 +192,8 @@
     isComposableMessageType(messageInfo.type) &&
     threadHasPermission(threadInfo, threadPermissions.MANAGE_PINS);
 
+  const inputState = React.useContext(InputStateContext);
+
   return React.useMemo(() => {
     if (!canTogglePin) {
       return null;
@@ -504,7 +204,11 @@
     const buttonContent = <CommIcon icon={iconName} size={18} />;
 
     const onClickTogglePin = () => {
-      pushModal(<TogglePinModal item={item} threadInfo={threadInfo} />);
+      pushModal(
+        <InputStateContext.Provider value={inputState}>
+          <TogglePinModal item={item} threadInfo={threadInfo} />
+        </InputStateContext.Provider>,
+      );
     };
 
     return {
@@ -512,7 +216,7 @@
       onClick: onClickTogglePin,
       label: isPinned ? 'Unpin' : 'Pin',
     };
-  }, [canTogglePin, isPinned, pushModal, item, threadInfo]);
+  }, [canTogglePin, inputState, isPinned, pushModal, item, threadInfo]);
 }
 
 function useMessageTooltipActions(
@@ -723,9 +427,6 @@
 }
 
 export {
-  findTooltipPosition,
-  calculateTooltipSize,
-  getMessageActionTooltipStyle,
   useMessageTooltipSidebarAction,
   useMessageTooltipReplyAction,
   useMessageReactAction,
diff --git a/web/utils/tooltip-utils.js b/web/utils/tooltip-utils.js
--- a/web/utils/tooltip-utils.js
+++ b/web/utils/tooltip-utils.js
@@ -1,41 +1,15 @@
 // @flow
 
 import invariant from 'invariant';
-import _debounce from 'lodash/debounce.js';
 import * as React from 'react';
 
-import { useModalContext } from 'lib/components/modal-provider.react.js';
-import type { ChatMessageInfoItem } from 'lib/selectors/chat-selectors.js';
-import { createMessageReply } from 'lib/shared/message-utils.js';
-import { useCanCreateReactionFromMessage } from 'lib/shared/reaction-utils.js';
-import {
-  threadHasPermission,
-  useSidebarExistsOrCanBeCreated,
-} from 'lib/shared/thread-utils.js';
-import {
-  isComposableMessageType,
-  messageTypes,
-} from 'lib/types/message-types.js';
-import type { ThreadInfo } from 'lib/types/thread-types.js';
-import { threadPermissions } from 'lib/types/thread-types.js';
-import { longAbsoluteDate } from 'lib/utils/date-utils.js';
-
 import { getAppContainerPositionInfo } from './window-utils.js';
 import {
   tooltipButtonStyle,
   tooltipLabelStyle,
   tooltipStyle,
 } from '../chat/chat-constants.js';
-import MessageTooltip from '../chat/message-tooltip.react.js';
 import type { PositionInfo } from '../chat/position-types.js';
-import { useTooltipContext } from '../chat/tooltip-provider.js';
-import CommIcon from '../CommIcon.react.js';
-import { InputStateContext } from '../input/input-state.js';
-import TogglePinModal from '../modals/chat/toggle-pin-modal.react.js';
-import {
-  useOnClickPendingSidebar,
-  useOnClickThread,
-} from '../selectors/thread-selectors.js';
 import { calculateMaxTextWidth } from '../utils/text-utils.js';
 
 export const tooltipPositions = Object.freeze({
@@ -341,394 +315,8 @@
   };
 }
 
-function useMessageTooltipSidebarAction(
-  item: ChatMessageInfoItem,
-  threadInfo: ThreadInfo,
-): ?MessageTooltipAction {
-  const { threadCreatedFromMessage, messageInfo } = item;
-  const sidebarExists = !!threadCreatedFromMessage;
-  const sidebarExistsOrCanBeCreated = useSidebarExistsOrCanBeCreated(
-    threadInfo,
-    item,
-  );
-  const openThread = useOnClickThread(threadCreatedFromMessage);
-  const openPendingSidebar = useOnClickPendingSidebar(messageInfo, threadInfo);
-  return React.useMemo(() => {
-    if (!sidebarExistsOrCanBeCreated) {
-      return null;
-    }
-    const buttonContent = <CommIcon icon="sidebar-filled" size={16} />;
-    const onClick = (event: SyntheticEvent<HTMLElement>) => {
-      if (threadCreatedFromMessage) {
-        openThread(event);
-      } else {
-        openPendingSidebar(event);
-      }
-    };
-    return {
-      actionButtonContent: buttonContent,
-      onClick,
-      label: sidebarExists ? 'Go to thread' : 'Create thread',
-    };
-  }, [
-    openPendingSidebar,
-    openThread,
-    sidebarExists,
-    sidebarExistsOrCanBeCreated,
-    threadCreatedFromMessage,
-  ]);
-}
-
-function useMessageTooltipReplyAction(
-  item: ChatMessageInfoItem,
-  threadInfo: ThreadInfo,
-): ?MessageTooltipAction {
-  const { messageInfo } = item;
-  const inputState = React.useContext(InputStateContext);
-  invariant(inputState, 'inputState is required');
-  const { addReply } = inputState;
-  return React.useMemo(() => {
-    if (
-      !isComposableMessageType(item.messageInfo.type) ||
-      !threadHasPermission(threadInfo, threadPermissions.VOICED)
-    ) {
-      return null;
-    }
-    const buttonContent = <CommIcon icon="reply-filled" size={18} />;
-    const onClick = () => {
-      if (!messageInfo.text) {
-        return;
-      }
-      addReply(createMessageReply(messageInfo.text));
-    };
-    return {
-      actionButtonContent: buttonContent,
-      onClick,
-      label: 'Reply',
-    };
-  }, [addReply, item.messageInfo.type, messageInfo, threadInfo]);
-}
-
-const copiedMessageDurationMs = 2000;
-function useMessageCopyAction(
-  item: ChatMessageInfoItem,
-): ?MessageTooltipAction {
-  const { messageInfo } = item;
-
-  const [successful, setSuccessful] = React.useState(false);
-  const resetStatusAfterTimeout = React.useRef(
-    _debounce(() => setSuccessful(false), copiedMessageDurationMs),
-  );
-
-  const onSuccess = React.useCallback(() => {
-    setSuccessful(true);
-    resetStatusAfterTimeout.current();
-  }, []);
-
-  React.useEffect(() => resetStatusAfterTimeout.current.cancel, []);
-
-  return React.useMemo(() => {
-    if (messageInfo.type !== messageTypes.TEXT) {
-      return null;
-    }
-    const buttonContent = <CommIcon icon="copy-filled" size={18} />;
-    const onClick = async () => {
-      try {
-        await navigator.clipboard.writeText(messageInfo.text);
-        onSuccess();
-      } catch (e) {
-        setSuccessful(false);
-      }
-    };
-    return {
-      actionButtonContent: buttonContent,
-      onClick,
-      label: successful ? 'Copied!' : 'Copy',
-    };
-  }, [messageInfo.text, messageInfo.type, onSuccess, successful]);
-}
-
-function useMessageReactAction(
-  item: ChatMessageInfoItem,
-  threadInfo: ThreadInfo,
-): ?MessageTooltipAction {
-  const { messageInfo } = item;
-
-  const { setShouldRenderEmojiKeyboard } = useTooltipContext();
-
-  const canCreateReactionFromMessage = useCanCreateReactionFromMessage(
-    threadInfo,
-    messageInfo,
-  );
-
-  return React.useMemo(() => {
-    if (!canCreateReactionFromMessage) {
-      return null;
-    }
-
-    const buttonContent = <CommIcon icon="emote-smile-filled" size={18} />;
-
-    const onClickReact = () => {
-      if (!setShouldRenderEmojiKeyboard) {
-        return;
-      }
-      setShouldRenderEmojiKeyboard(true);
-    };
-
-    return {
-      actionButtonContent: buttonContent,
-      onClick: onClickReact,
-      label: 'React',
-    };
-  }, [canCreateReactionFromMessage, setShouldRenderEmojiKeyboard]);
-}
-
-function useMessageTogglePinAction(
-  item: ChatMessageInfoItem,
-  threadInfo: ThreadInfo,
-): ?MessageTooltipAction {
-  const { pushModal } = useModalContext();
-  const { messageInfo, isPinned } = item;
-
-  const canTogglePin =
-    isComposableMessageType(messageInfo.type) &&
-    threadHasPermission(threadInfo, threadPermissions.MANAGE_PINS);
-
-  return React.useMemo(() => {
-    if (!canTogglePin) {
-      return null;
-    }
-
-    const iconName = isPinned ? 'unpin' : 'pin';
-
-    const buttonContent = <CommIcon icon={iconName} size={18} />;
-
-    const onClickTogglePin = () => {
-      pushModal(<TogglePinModal item={item} threadInfo={threadInfo} />);
-    };
-
-    return {
-      actionButtonContent: buttonContent,
-      onClick: onClickTogglePin,
-      label: isPinned ? 'Unpin' : 'Pin',
-    };
-  }, [canTogglePin, isPinned, pushModal, item, threadInfo]);
-}
-
-function useMessageTooltipActions(
-  item: ChatMessageInfoItem,
-  threadInfo: ThreadInfo,
-): $ReadOnlyArray<MessageTooltipAction> {
-  const sidebarAction = useMessageTooltipSidebarAction(item, threadInfo);
-  const replyAction = useMessageTooltipReplyAction(item, threadInfo);
-  const copyAction = useMessageCopyAction(item);
-  const reactAction = useMessageReactAction(item, threadInfo);
-  const togglePinAction = useMessageTogglePinAction(item, threadInfo);
-  return React.useMemo(
-    () =>
-      [
-        replyAction,
-        sidebarAction,
-        copyAction,
-        reactAction,
-        togglePinAction,
-      ].filter(Boolean),
-    [replyAction, sidebarAction, copyAction, reactAction, togglePinAction],
-  );
-}
-
-type UseMessageTooltipArgs = {
-  +availablePositions: $ReadOnlyArray<TooltipPosition>,
-  +item: ChatMessageInfoItem,
-  +threadInfo: ThreadInfo,
-};
-
-type UseMessageTooltipResult = {
-  onMouseEnter: (event: SyntheticEvent<HTMLElement>) => void,
-  onMouseLeave: ?() => mixed,
-};
-
-type CreateTooltipParams = {
-  +tooltipMessagePosition: ?PositionInfo,
-  +tooltipSize: TooltipSize,
-  +availablePositions: $ReadOnlyArray<TooltipPosition>,
-  +containsInlineEngagement: boolean,
-  +tooltipActions: $ReadOnlyArray<MessageTooltipAction>,
-  +messageTimestamp: string,
-  +item: ChatMessageInfoItem,
-  +threadInfo: ThreadInfo,
-};
-
-function createTooltip(params: CreateTooltipParams) {
-  const {
-    tooltipMessagePosition,
-    tooltipSize,
-    availablePositions,
-    containsInlineEngagement,
-    tooltipActions,
-    messageTimestamp,
-    item,
-    threadInfo,
-  } = params;
-  if (!tooltipMessagePosition) {
-    return;
-  }
-  const tooltipPosition = findTooltipPosition({
-    sourcePositionInfo: tooltipMessagePosition,
-    tooltipSize,
-    availablePositions,
-    defaultPosition: availablePositions[0],
-    preventDisplayingBelowSource: containsInlineEngagement,
-  });
-  if (!tooltipPosition) {
-    return;
-  }
-
-  const tooltipPositionStyle = getMessageActionTooltipStyle({
-    tooltipPosition,
-    sourcePositionInfo: tooltipMessagePosition,
-    tooltipSize,
-  });
-
-  const tooltip = (
-    <MessageTooltip
-      actions={tooltipActions}
-      messageTimestamp={messageTimestamp}
-      tooltipPositionStyle={tooltipPositionStyle}
-      tooltipSize={tooltipSize}
-      item={item}
-      threadInfo={threadInfo}
-    />
-  );
-  return { tooltip, tooltipPositionStyle };
-}
-
-function useMessageTooltip({
-  availablePositions,
-  item,
-  threadInfo,
-}: UseMessageTooltipArgs): UseMessageTooltipResult {
-  const [onMouseLeave, setOnMouseLeave] = React.useState<?() => mixed>(null);
-
-  const { renderTooltip } = useTooltipContext();
-  const tooltipActions = useMessageTooltipActions(item, threadInfo);
-
-  const containsInlineEngagement = !!item.threadCreatedFromMessage;
-
-  const messageTimestamp = React.useMemo(() => {
-    const time = item.messageInfo.time;
-    return longAbsoluteDate(time);
-  }, [item.messageInfo.time]);
-
-  const tooltipSize = React.useMemo(() => {
-    if (typeof document === 'undefined') {
-      return {
-        width: 0,
-        height: 0,
-      };
-    }
-    const tooltipLabels = tooltipActions.map(action => action.label);
-    return calculateTooltipSize({
-      tooltipLabels,
-      timestamp: messageTimestamp,
-    });
-  }, [messageTimestamp, tooltipActions]);
-
-  const updateTooltip = React.useRef();
-  const [tooltipMessagePosition, setTooltipMessagePosition] = React.useState();
-
-  const onMouseEnter = React.useCallback(
-    (event: SyntheticEvent<HTMLElement>) => {
-      if (!renderTooltip) {
-        return;
-      }
-      const rect = event.currentTarget.getBoundingClientRect();
-      const { top, bottom, left, right, height, width } = rect;
-      const messagePosition = { top, bottom, left, right, height, width };
-      setTooltipMessagePosition(messagePosition);
-
-      const tooltipResult = createTooltip({
-        tooltipMessagePosition,
-        tooltipSize,
-        availablePositions,
-        containsInlineEngagement,
-        tooltipActions,
-        messageTimestamp,
-        item,
-        threadInfo,
-      });
-      if (!tooltipResult) {
-        return;
-      }
-
-      const { tooltip, tooltipPositionStyle } = tooltipResult;
-      const renderTooltipResult = renderTooltip({
-        newNode: tooltip,
-        tooltipPositionStyle,
-      });
-      if (renderTooltipResult) {
-        const { onMouseLeaveCallback: callback } = renderTooltipResult;
-        setOnMouseLeave((() => callback: () => () => mixed));
-        updateTooltip.current = renderTooltipResult.updateTooltip;
-      }
-    },
-    [
-      availablePositions,
-      containsInlineEngagement,
-      item,
-      messageTimestamp,
-      renderTooltip,
-      threadInfo,
-      tooltipActions,
-      tooltipMessagePosition,
-      tooltipSize,
-    ],
-  );
-
-  React.useEffect(() => {
-    if (!updateTooltip.current) {
-      return;
-    }
-
-    const tooltipResult = createTooltip({
-      tooltipMessagePosition,
-      tooltipSize,
-      availablePositions,
-      containsInlineEngagement,
-      tooltipActions,
-      messageTimestamp,
-      item,
-      threadInfo,
-    });
-    if (!tooltipResult) {
-      return;
-    }
-
-    updateTooltip.current?.(tooltipResult.tooltip);
-  }, [
-    availablePositions,
-    containsInlineEngagement,
-    item,
-    messageTimestamp,
-    threadInfo,
-    tooltipActions,
-    tooltipMessagePosition,
-    tooltipSize,
-  ]);
-
-  return {
-    onMouseEnter,
-    onMouseLeave,
-  };
-}
-
 export {
   findTooltipPosition,
   calculateTooltipSize,
   getMessageActionTooltipStyle,
-  useMessageTooltipSidebarAction,
-  useMessageTooltipReplyAction,
-  useMessageReactAction,
-  useMessageTooltipActions,
-  useMessageTooltip,
 };