diff --git a/web/chat/message-tooltip.css b/web/chat/message-tooltip.css
index 734ed4055..f0a9b77af 100644
--- a/web/chat/message-tooltip.css
+++ b/web/chat/message-tooltip.css
@@ -1,63 +1,73 @@
+div.container {
+  display: flex;
+  flex-direction: row;
+}
+
+div.containerLeftAlign,
+div.containerCenterAlign {
+  flex-direction: row-reverse;
+}
+
 div.messageTooltipContainer {
   display: flex;
   flex-direction: column;
   align-items: center;
   font-size: var(--s-font-14);
 }
 
 div.messageActionContainer {
   display: flex;
   flex-direction: row;
   align-items: center;
   justify-content: center;
   background-color: var(--message-action-tooltip-bg);
   border-radius: 8px;
   width: fit-content;
   box-shadow: var(--message-action-tooltip-bg) 0 2px 8px;
 }
 
 div.messageActionButtons {
   display: flex;
   font-size: 16px;
 }
 div.messageActionButtons svg {
   padding: 10px 6px 6px;
   color: var(--color-disabled);
 }
 
 div.messageActionButtons svg:hover,
 div.messageActionButtons span:hover {
   cursor: pointer;
   color: var(--fg);
 }
 
 div.messageTooltipButton {
   display: flex;
   align-items: center;
   justify-content: center;
 }
 
 div.messageTooltipLabel {
   display: flex;
   flex-direction: row;
   align-items: center;
   justify-content: center;
   background-color: var(--message-action-tooltip-bg);
   color: var(--tool-tip-color);
   border-radius: 8px;
   overflow: auto;
   white-space: nowrap;
   box-shadow: var(--message-action-tooltip-bg) 0 2px 8px;
 }
 
 div.leftTooltipAlign {
   align-items: flex-start;
 }
 
 div.centerTooltipAlign {
   align-items: center;
 }
 
 div.rightTooltipAlign {
   align-items: flex-end;
 }
diff --git a/web/chat/message-tooltip.react.js b/web/chat/message-tooltip.react.js
index eb3661622..4ef6f1c1e 100644
--- a/web/chat/message-tooltip.react.js
+++ b/web/chat/message-tooltip.react.js
@@ -1,111 +1,169 @@
 // @flow
 
+import data from '@emoji-mart/data';
+import Picker from '@emoji-mart/react';
 import classNames from 'classnames';
 import * as React from 'react';
 
+import type { ChatMessageInfoItem } from 'lib/selectors/chat-selectors';
+import { localIDPrefix } from 'lib/shared/message-utils';
+import type { ThreadInfo } from 'lib/types/thread-types';
+
+import { useSelector } from '../redux/redux-utils';
 import { type MessageTooltipAction } from '../utils/tooltip-utils';
 import {
   tooltipButtonStyle,
   tooltipLabelStyle,
   tooltipStyle,
 } from './chat-constants';
 import css from './message-tooltip.css';
+import { useSendReaction } from './reaction-message-utils';
+import { useTooltipContext } from './tooltip-provider';
 
 type MessageTooltipProps = {
   +actions: $ReadOnlyArray<MessageTooltipAction>,
   +messageTimestamp: string,
   +alignment?: 'left' | 'center' | 'right',
+  +item: ChatMessageInfoItem,
+  +threadInfo: ThreadInfo,
 };
 function MessageTooltip(props: MessageTooltipProps): React.Node {
-  const { actions, messageTimestamp, alignment = 'left' } = props;
+  const {
+    actions,
+    messageTimestamp,
+    alignment = 'left',
+    item,
+    threadInfo,
+  } = props;
+  const { messageInfo, reactions } = item;
+
   const [activeTooltipLabel, setActiveTooltipLabel] = React.useState<?string>();
+
+  const { renderEmojiKeyboard } = useTooltipContext();
+
   const messageActionButtonsContainerClassName = classNames(
     css.messageActionContainer,
     css.messageActionButtons,
   );
 
   const messageTooltipButtonStyle = React.useMemo(() => tooltipButtonStyle, []);
 
   const tooltipButtons = React.useMemo(() => {
     if (!actions || actions.length === 0) {
       return null;
     }
     const buttons = actions.map(({ label, onClick, actionButtonContent }) => {
       const onMouseEnter = () => {
         setActiveTooltipLabel(label);
       };
       const onMouseLeave = () =>
         setActiveTooltipLabel(oldLabel =>
           label === oldLabel ? null : oldLabel,
         );
 
       return (
         <div
           onMouseEnter={onMouseEnter}
           onMouseLeave={onMouseLeave}
           key={label}
           onClick={onClick}
           style={messageTooltipButtonStyle}
           className={css.messageTooltipButton}
         >
           {actionButtonContent}
         </div>
       );
     });
     return (
       <div className={messageActionButtonsContainerClassName}>{buttons}</div>
     );
   }, [
     actions,
     messageActionButtonsContainerClassName,
     messageTooltipButtonStyle,
   ]);
 
   const messageTooltipLabelStyle = React.useMemo(() => tooltipLabelStyle, []);
   const messageTooltipTopLabelStyle = React.useMemo(
     () => ({
       height: `${tooltipLabelStyle.height + 2 * tooltipLabelStyle.padding}px`,
     }),
     [],
   );
 
   const tooltipLabel = React.useMemo(() => {
     if (!activeTooltipLabel) {
       return null;
     }
     return (
       <div className={css.messageTooltipLabel} style={messageTooltipLabelStyle}>
         {activeTooltipLabel}
       </div>
     );
   }, [activeTooltipLabel, messageTooltipLabelStyle]);
 
   const tooltipTimestamp = React.useMemo(() => {
     if (!messageTimestamp) {
       return null;
     }
     return (
       <div className={css.messageTooltipLabel} style={messageTooltipLabelStyle}>
         {messageTimestamp}
       </div>
     );
   }, [messageTimestamp, messageTooltipLabelStyle]);
 
+  const nextLocalID = useSelector(state => state.nextLocalID);
+  const localID = `${localIDPrefix}${nextLocalID}`;
+
+  const sendReaction = useSendReaction(messageInfo.id, localID, threadInfo.id);
+
+  const onEmojiSelect = React.useCallback(
+    emoji => {
+      const reactionInput = emoji.native;
+      const viewerReacted = !!reactions.get(reactionInput)?.viewerReacted;
+      const action = viewerReacted ? 'remove_reaction' : 'add_reaction';
+
+      sendReaction(reactionInput, action);
+    },
+    [sendReaction, reactions],
+  );
+
+  const emojiKeyboard = React.useMemo(() => {
+    if (!renderEmojiKeyboard) {
+      return null;
+    }
+    return <Picker data={data} onEmojiSelect={onEmojiSelect} />;
+  }, [onEmojiSelect, renderEmojiKeyboard]);
+
   const messageTooltipContainerStyle = React.useMemo(() => tooltipStyle, []);
 
-  const containerClassNames = classNames(css.messageTooltipContainer, {
+  const containerClassName = classNames({
+    [css.container]: true,
+    [css.containerLeftAlign]: alignment === 'left',
+    [css.containerCenterAlign]: alignment === 'center',
+  });
+
+  const messageTooltipContainerClassNames = classNames({
+    [css.messageTooltipContainer]: true,
     [css.leftTooltipAlign]: alignment === 'left',
     [css.centerTooltipAlign]: alignment === 'center',
     [css.rightTooltipAlign]: alignment === 'right',
   });
 
   return (
-    <div className={containerClassNames} style={messageTooltipContainerStyle}>
-      <div style={messageTooltipTopLabelStyle}>{tooltipLabel}</div>
-      {tooltipButtons}
-      {tooltipTimestamp}
+    <div className={containerClassName}>
+      {emojiKeyboard}
+      <div
+        className={messageTooltipContainerClassNames}
+        style={messageTooltipContainerStyle}
+      >
+        <div style={messageTooltipTopLabelStyle}>{tooltipLabel}</div>
+        {tooltipButtons}
+        {tooltipTimestamp}
+      </div>
     </div>
   );
 }
 
 export default MessageTooltip;
diff --git a/web/chat/reaction-message-utils.js b/web/chat/reaction-message-utils.js
index aad5804eb..21bc48281 100644
--- a/web/chat/reaction-message-utils.js
+++ b/web/chat/reaction-message-utils.js
@@ -1,104 +1,104 @@
 // @flow
 
 import invariant from 'invariant';
 import * as React from 'react';
 
 import {
   sendReactionMessage,
   sendReactionMessageActionTypes,
 } from 'lib/actions/message-actions';
 import { useModalContext } from 'lib/components/modal-provider.react';
 import { messageTypes } from 'lib/types/message-types';
 import type { RawReactionMessageInfo } from 'lib/types/messages/reaction';
 import {
   useDispatchActionPromise,
   useServerCall,
 } from 'lib/utils/action-utils';
 import { cloneError } from 'lib/utils/errors';
 
 import Alert from '../modals/alert.react';
 import { useSelector } from '../redux/redux-utils';
 
-function useOnClickReact(
+function useSendReaction(
   messageID: ?string,
   localID: string,
   threadID: string,
 ): (reaction: string, action: 'add_reaction' | 'remove_reaction') => mixed {
   const { pushModal } = useModalContext();
 
   const viewerID = useSelector(
     state => state.currentUserInfo && state.currentUserInfo.id,
   );
 
   const callSendReactionMessage = useServerCall(sendReactionMessage);
   const dispatchActionPromise = useDispatchActionPromise();
 
   return React.useCallback(
     (reaction, action) => {
       if (!messageID) {
         return;
       }
 
       invariant(viewerID, 'viewerID should be set');
 
       const reactionMessagePromise = (async () => {
         try {
           const result = await callSendReactionMessage({
             threadID,
             localID,
             targetMessageID: messageID,
             reaction,
             action,
           });
           return {
             localID,
             serverID: result.id,
             threadID,
             time: result.time,
             interface: result.interface,
           };
         } catch (e) {
           pushModal(
             <Alert title="Couldn’t send the reaction">
               Please try again later
             </Alert>,
           );
 
           const copy = cloneError(e);
           copy.localID = localID;
           copy.threadID = threadID;
           throw copy;
         }
       })();
 
       const startingPayload: RawReactionMessageInfo = {
         type: messageTypes.REACTION,
         threadID,
         localID,
         creatorID: viewerID,
         time: Date.now(),
         targetMessageID: messageID,
         reaction,
         action,
       };
 
       dispatchActionPromise(
         sendReactionMessageActionTypes,
         reactionMessagePromise,
         undefined,
         startingPayload,
       );
     },
     [
       messageID,
       viewerID,
       threadID,
       localID,
       dispatchActionPromise,
       callSendReactionMessage,
       pushModal,
     ],
   );
 }
 
-export { useOnClickReact };
+export { useSendReaction };
diff --git a/web/utils/tooltip-utils.js b/web/utils/tooltip-utils.js
index 098d0dcdf..2ac0ebe4e 100644
--- a/web/utils/tooltip-utils.js
+++ b/web/utils/tooltip-utils.js
@@ -1,693 +1,698 @@
 // @flow
 
 import invariant from 'invariant';
 import _debounce from 'lodash/debounce';
 import * as React from 'react';
 
 import type { ChatMessageInfoItem } from 'lib/selectors/chat-selectors';
-import { localIDPrefix, createMessageReply } from 'lib/shared/message-utils';
+import { createMessageReply } from 'lib/shared/message-utils';
 import { useCanCreateReactionFromMessage } from 'lib/shared/reaction-utils';
 import {
   threadHasPermission,
   useSidebarExistsOrCanBeCreated,
 } from 'lib/shared/thread-utils';
 import { isComposableMessageType, messageTypes } from 'lib/types/message-types';
 import type { ThreadInfo } from 'lib/types/thread-types';
 import { threadPermissions } from 'lib/types/thread-types';
 import { longAbsoluteDate } from 'lib/utils/date-utils';
 
 import {
   tooltipButtonStyle,
   tooltipLabelStyle,
   tooltipStyle,
 } from '../chat/chat-constants';
-import MessageLikeTooltipButton from '../chat/message-like-tooltip-button.react';
 import MessageTooltip from '../chat/message-tooltip.react';
 import type { PositionInfo } from '../chat/position-types';
-import { useOnClickReact } from '../chat/reaction-message-utils';
 import { useTooltipContext } from '../chat/tooltip-provider';
 import CommIcon from '../CommIcon.react';
 import { InputStateContext } from '../input/input-state';
-import { useSelector } from '../redux/redux-utils';
 import {
   useOnClickPendingSidebar,
   useOnClickThread,
 } from '../selectors/thread-selectors';
+import SWMansionIcon from '../SWMansionIcon.react';
 import { calculateMaxTextWidth } from '../utils/text-utils';
 
 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',
 });
 
 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 appTopBarHeight = 65;
 
 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 {
   if (!window) {
     return defaultPosition;
   }
   const appContainerPositionInfo: PositionInfo = {
     height: window.innerHeight - appTopBarHeight,
     width: window.innerWidth,
     top: appTopBarHeight,
     bottom: window.innerHeight,
     left: 0,
     right: window.innerWidth,
   };
 
   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,
   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, reactions } = item;
-
-  const nextLocalID = useSelector(state => state.nextLocalID);
-  const localID = `${localIDPrefix}${nextLocalID}`;
-
-  const reactionInput = '👍';
-  const viewerReacted = !!reactions.get(reactionInput)?.viewerReacted;
-  const action = viewerReacted ? 'remove_reaction' : 'add_reaction';
-
-  const onClickReact = useOnClickReact(messageInfo.id, localID, threadInfo.id);
+  const { messageInfo } = item;
 
-  const onClick = React.useCallback(() => onClickReact(reactionInput, action), [
-    action,
-    onClickReact,
-  ]);
+  const { setRenderEmojiKeyboard } = useTooltipContext();
 
   const canCreateReactionFromMessage = useCanCreateReactionFromMessage(
     threadInfo,
     messageInfo,
   );
 
   return React.useMemo(() => {
     if (!canCreateReactionFromMessage) {
       return null;
     }
 
-    const buttonContent = (
-      <MessageLikeTooltipButton viewerReacted={viewerReacted} />
-    );
+    const buttonContent = <SWMansionIcon icon="emote-smile" size={18} />;
+
+    const onClickReact = () => {
+      if (!setRenderEmojiKeyboard) {
+        return;
+      }
+      setRenderEmojiKeyboard(true);
+    };
 
     return {
       actionButtonContent: buttonContent,
-      onClick,
-      label: viewerReacted ? 'Unlike' : 'Like',
+      onClick: onClickReact,
+      label: 'React',
     };
-  }, [canCreateReactionFromMessage, onClick, viewerReacted]);
+  }, [canCreateReactionFromMessage, setRenderEmojiKeyboard]);
 }
 
 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);
   return React.useMemo(
     () => [replyAction, sidebarAction, copyAction, reactAction].filter(Boolean),
     [replyAction, sidebarAction, copyAction, reactAction],
   );
 }
 
 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 { alignment } = tooltipPositionStyle;
 
   const tooltip = (
     <MessageTooltip
       actions={tooltipActions}
       messageTimestamp={messageTimestamp}
       alignment={alignment}
+      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,
 };