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
@@ -1,7 +1,6 @@
 // @flow
 
 import classNames from 'classnames';
-import invariant from 'invariant';
 import * as React from 'react';
 import {
   Circle as CircleIcon,
@@ -20,7 +19,6 @@
 import FailedSend from './failed-send.react';
 import { InlineSidebar } from './inline-sidebar.react';
 import MessageActionButtons from './message-action-buttons';
-import MessageReplyButton from './message-reply-button.react';
 import {
   type OnMessagePositionWithContainerInfo,
   type MessagePositionInfo,
@@ -120,34 +118,17 @@
       );
     }
 
-    let replyButton;
+    let messageActionButtons;
     if (
       this.props.mouseOverMessagePosition &&
       this.props.mouseOverMessagePosition.item.messageInfo.id === id &&
-      this.props.canReply
-    ) {
-      const { inputState } = this.props;
-      invariant(inputState, 'inputState should be set in ComposedMessage');
-      replyButton = (
-        <MessageReplyButton
-          messagePositionInfo={this.props.mouseOverMessagePosition}
-          onReplyClick={this.onMouseLeave}
-          inputState={inputState}
-        />
-      );
-    }
-
-    let messageActionButton;
-    if (
-      this.props.mouseOverMessagePosition &&
-      this.props.mouseOverMessagePosition.item.messageInfo.id === id &&
-      this.props.sidebarExistsOrCanBeCreated
+      (this.props.sidebarExistsOrCanBeCreated || this.props.canReply)
     ) {
       const availableTooltipPositions = isViewer
         ? availableTooltipPositionsForViewerMessage
         : availableTooltipPositionsForNonViewerMessage;
 
-      messageActionButton = (
+      messageActionButtons = (
         <MessageActionButtons
           threadInfo={threadInfo}
           item={item}
@@ -155,41 +136,35 @@
             this.props.mouseOverMessagePosition.containerPosition
           }
           availableTooltipPositions={availableTooltipPositions}
+          setMouseOverMessagePosition={this.props.setMouseOverMessagePosition}
+          mouseOverMessagePosition={this.props.mouseOverMessagePosition}
+          canReply={this.props.canReply}
+          inputState={this.props.inputState}
+          sidebarExistsOrCanBeCreated={this.props.sidebarExistsOrCanBeCreated}
         />
       );
     }
 
-    let viewerActionLinks, nonViewerActionLinks;
-    if (isViewer && (replyButton || messageActionButton)) {
-      viewerActionLinks = (
-        <div
-          className={classNames(
-            css.messageActionActiveArea,
-            css.viewerMessageActionActiveArea,
-          )}
-        >
-          <div className={css.messageActionContainer}>
-            {messageActionButton}
-            {replyButton}
-          </div>
-        </div>
-      );
-    } else if (replyButton || messageActionButton) {
-      nonViewerActionLinks = (
-        <div
-          className={classNames(
-            css.messageActionActiveArea,
-            css.nonViewerMessageActiveArea,
-          )}
-        >
+    let messageActionLinks;
+    if (messageActionButtons) {
+      const actionLinksClassName = classNames({
+        [css.messageActionActiveArea]: true,
+        [css.viewerMessageActionActiveArea]: isViewer,
+        [css.nonViewerMessageActiveArea]: !isViewer,
+      });
+
+      messageActionLinks = (
+        <div className={actionLinksClassName}>
           <div className={css.messageActionContainer}>
-            {replyButton}
-            {messageActionButton}
+            {messageActionButtons}
           </div>
         </div>
       );
     }
 
+    const viewerActionLinks = isViewer ? messageActionLinks : null;
+    const nonViewerActionLinks = !isViewer ? messageActionLinks : null;
+
     let inlineSidebar = null;
     if (item.threadCreatedFromMessage) {
       const positioning = isViewer ? 'right' : 'left';
diff --git a/web/chat/message-action-buttons.js b/web/chat/message-action-buttons.js
--- a/web/chat/message-action-buttons.js
+++ b/web/chat/message-action-buttons.js
@@ -7,14 +7,18 @@
 import type { ChatMessageInfoItem } from 'lib/selectors/chat-selectors';
 import type { ThreadInfo } from 'lib/types/thread-types';
 
+import type { InputState } from '../input/input-state.js';
 import {
   useOnClickThread,
   useOnClickPendingSidebar,
 } from '../selectors/nav-selectors';
 import SWMansionIcon from '../SWMansionIcon.react';
 import css from './message-action-buttons.css';
+import MessageReplyButton from './message-reply-button.react';
 import type {
   ItemAndContainerPositionInfo,
+  MessagePositionInfo,
+  OnMessagePositionWithContainerInfo,
   PositionInfo,
 } from './position-types';
 import { tooltipPositions, type TooltipPosition } from './tooltip-utils';
@@ -34,6 +38,13 @@
   +item: ChatMessageInfoItem,
   +containerPosition: PositionInfo,
   +availableTooltipPositions: $ReadOnlyArray<TooltipPosition>,
+  +setMouseOverMessagePosition?: (
+    messagePositionInfo: MessagePositionInfo,
+  ) => void,
+  +mouseOverMessagePosition?: OnMessagePositionWithContainerInfo,
+  +canReply?: boolean,
+  +inputState?: ?InputState,
+  +sidebarExistsOrCanBeCreated?: boolean,
 };
 function MessageActionButtons(props: MessageActionButtonsProps): React.Node {
   const {
@@ -41,7 +52,13 @@
     item,
     containerPosition,
     availableTooltipPositions,
+    setMouseOverMessagePosition,
+    mouseOverMessagePosition,
+    canReply,
+    inputState,
+    sidebarExistsOrCanBeCreated,
   } = props;
+
   const [tooltipVisible, setTooltipVisible] = React.useState(false);
   const [pointingTo, setPointingTo] = React.useState();
 
@@ -98,6 +115,14 @@
     [onPendingSidebarOpen, onThreadOpen, threadCreatedFromMessage],
   );
 
+  const onReplyButtonClick = React.useCallback(() => {
+    invariant(
+      setMouseOverMessagePosition,
+      'setMouseOverMessagePosition should be set if replyButton exists',
+    );
+    setMouseOverMessagePosition({ type: 'off', item: item });
+  }, [item, setMouseOverMessagePosition]);
+
   const sidebarTooltipButtonText = threadCreatedFromMessage
     ? openSidebarText
     : createSidebarText;
@@ -116,8 +141,25 @@
     );
   }
 
-  return (
-    <div className={css.messageActionButton}>
+  let replyButton;
+  if (canReply) {
+    invariant(inputState, 'inputState must be set if replyButton exists');
+    invariant(
+      mouseOverMessagePosition,
+      'mouseOverMessagePosition must be set if replyButton exists',
+    );
+    replyButton = (
+      <MessageReplyButton
+        messagePositionInfo={mouseOverMessagePosition}
+        onReplyClick={onReplyButtonClick}
+        inputState={inputState}
+      />
+    );
+  }
+
+  let sidebarButton;
+  if (sidebarExistsOrCanBeCreated) {
+    sidebarButton = (
       <div
         className={css.messageActionLinkIcon}
         onMouseLeave={hideTooltip}
@@ -127,6 +169,13 @@
         <SWMansionIcon icon="message-circle-lines" size={18} />
         {tooltipMenu}
       </div>
+    );
+  }
+
+  return (
+    <div className={css.messageActionButton}>
+      {sidebarButton}
+      {replyButton}
     </div>
   );
 }