diff --git a/web/chat/chat-message-list.react.js b/web/chat/chat-message-list.react.js
--- a/web/chat/chat-message-list.react.js
+++ b/web/chat/chat-message-list.react.js
@@ -32,6 +32,7 @@
 import { useSelector } from '../redux/redux-utils';
 import css from './chat-message-list.css';
 import { MessageListContext } from './message-list-types';
+import MessageTimestampTooltip from './message-timestamp-tooltip.react';
 import Message from './message.react';
 import type {
   OnMessagePositionWithContainerInfo,
@@ -237,6 +238,17 @@
     invariant(inputState, 'InputState should be set');
     const messages = messageListData.map(this.renderItem);
 
+    let tooltip;
+    if (this.state.mouseOverMessagePosition) {
+      const messagePositionInfo = this.state.mouseOverMessagePosition;
+      tooltip = (
+        <MessageTimestampTooltip
+          messagePositionInfo={messagePositionInfo}
+          timeZone={this.props.timeZone}
+        />
+      );
+    }
+
     let relationshipPrompt;
     if (threadInfo) {
       relationshipPrompt = <RelationshipPrompt threadInfo={threadInfo} />;
@@ -252,6 +264,7 @@
         <div className={messageContainerStyle} ref={this.messageContainerRef}>
           {messages}
         </div>
+        {tooltip}
       </div>
     );
   }
diff --git a/web/chat/message-timestamp-tooltip.css b/web/chat/message-timestamp-tooltip.css
new file mode 100644
--- /dev/null
+++ b/web/chat/message-timestamp-tooltip.css
@@ -0,0 +1,53 @@
+div.messageLeftTooltip:after {
+  top: 7px;
+  right: -14px;
+  border-color: transparent transparent transparent var(--tool-tip-bg);
+}
+div.messageRightTooltip:after {
+  top: 7px;
+  left: -14px;
+  border-color: transparent var(--tool-tip-bg) transparent transparent;
+}
+div.messageTopLeftTooltip:after {
+  bottom: -14px;
+  left: 4px;
+  border-color: var(--tool-tip-bg) transparent transparent transparent;
+}
+div.messageTopRightTooltip:after {
+  bottom: -14px;
+  right: 4px;
+  border-color: var(--tool-tip-bg) transparent transparent transparent;
+}
+div.messageBottomLeftTooltip:after {
+  top: -14px;
+  left: 4px;
+  border-color: transparent transparent var(--tool-tip-bg) transparent;
+}
+div.messageBottomRightTooltip:after {
+  top: -14px;
+  right: 4px;
+  border-color: transparent transparent var(--tool-tip-bg) transparent;
+}
+
+div.messageActionActiveArea {
+  position: absolute;
+  display: flex;
+  top: 0;
+  bottom: 0;
+  align-items: center;
+  padding: 0 12px;
+}
+
+div.viewerMessageActionActiveArea {
+  right: 100%;
+}
+div.nonViewerMessageActiveArea {
+  left: 100%;
+}
+div.messageActionActiveArea > div + div {
+  margin-left: 4px;
+}
+
+div.messageActionLinkIcon:hover {
+  cursor: pointer;
+}
diff --git a/web/chat/message-timestamp-tooltip.react.js b/web/chat/message-timestamp-tooltip.react.js
new file mode 100644
--- /dev/null
+++ b/web/chat/message-timestamp-tooltip.react.js
@@ -0,0 +1,148 @@
+// @flow
+
+import invariant from 'invariant';
+import * as React from 'react';
+
+import { isComposableMessageType } from 'lib/types/message-types';
+import { longAbsoluteDate } from 'lib/utils/date-utils';
+
+import css from './message-timestamp-tooltip.css';
+import type { OnMessagePositionWithContainerInfo } from './position-types';
+import {
+  type TooltipPosition,
+  tooltipPositions,
+  sizeOfTooltipArrow,
+} from './tooltip-utils';
+import {
+  TooltipMenu,
+  type TooltipStyle,
+  TooltipTextItem,
+} from './tooltip.react';
+
+const availablePositionsForComposedViewerMessage = [
+  tooltipPositions.BOTTOM_RIGHT,
+];
+const availablePositionsForNonComposedOrNonViewerMessage = [
+  tooltipPositions.LEFT,
+];
+
+type Props = {
+  +messagePositionInfo: OnMessagePositionWithContainerInfo,
+  +timeZone: ?string,
+};
+function MessageTimestampTooltip(props: Props): React.Node {
+  const { messagePositionInfo, timeZone } = props;
+  const { time, creator, type } = messagePositionInfo.item.messageInfo;
+  console.log(messagePositionInfo);
+
+  const text = React.useMemo(() => longAbsoluteDate(time, timeZone), [
+    time,
+    timeZone,
+  ]);
+  const availableTooltipPositions = React.useMemo(() => {
+    const { isViewer } = creator;
+    const isComposed = isComposableMessageType(type);
+    return isComposed && isViewer
+      ? availablePositionsForComposedViewerMessage
+      : availablePositionsForNonComposedOrNonViewerMessage;
+  }, [creator, type]);
+
+  const { messagePosition, containerPosition } = messagePositionInfo;
+  const pointingToInfo = React.useMemo(() => {
+    return {
+      containerPosition,
+      itemPosition: messagePosition,
+    };
+  }, [messagePosition, containerPosition]);
+
+  const getTooltipStyle = React.useCallback(
+    (tooltipPosition: TooltipPosition) =>
+      getTimestampTooltipStyle(messagePositionInfo, tooltipPosition),
+    [messagePositionInfo],
+  );
+  return (
+    <TooltipMenu
+      availableTooltipPositions={availableTooltipPositions}
+      targetPositionInfo={pointingToInfo}
+      layoutPosition="absolute"
+      getStyle={getTooltipStyle}
+    >
+      <TooltipTextItem text={text} />
+    </TooltipMenu>
+  );
+}
+
+function getTimestampTooltipStyle(
+  messagePositionInfo: OnMessagePositionWithContainerInfo,
+  tooltipPosition: TooltipPosition,
+): TooltipStyle {
+  const { messagePosition, containerPosition } = messagePositionInfo;
+  const { height: containerHeight, width: containerWidth } = containerPosition;
+
+  let style, className;
+  if (tooltipPosition === tooltipPositions.LEFT) {
+    const centerOfMessage = messagePosition.top + messagePosition.height / 2;
+    const tooltipPointing = Math.max(
+      Math.min(centerOfMessage, containerHeight),
+      0,
+    );
+    style = {
+      right: containerWidth - messagePosition.left + sizeOfTooltipArrow,
+      top: tooltipPointing,
+    };
+    className = css.messageLeftTooltip;
+  } else if (tooltipPosition === tooltipPositions.RIGHT) {
+    const centerOfMessage = messagePosition.top + messagePosition.height / 2;
+    const tooltipPointing = Math.max(
+      Math.min(centerOfMessage, containerHeight),
+      0,
+    );
+    style = {
+      left: messagePosition.right + sizeOfTooltipArrow,
+      top: tooltipPointing,
+    };
+    className = css.messageRightTooltip;
+  } else if (tooltipPosition === tooltipPositions.TOP_LEFT) {
+    const tooltipPointing = Math.min(
+      containerHeight - messagePosition.top,
+      containerHeight,
+    );
+    style = {
+      left: messagePosition.left,
+      bottom: tooltipPointing + sizeOfTooltipArrow,
+    };
+    className = css.messageTopLeftTooltip;
+  } else if (tooltipPosition === tooltipPositions.TOP_RIGHT) {
+    const tooltipPointing = Math.min(
+      containerHeight - messagePosition.top,
+      containerHeight,
+    );
+    style = {
+      right: containerWidth - messagePosition.right,
+      bottom: tooltipPointing + sizeOfTooltipArrow,
+    };
+    className = css.messageTopRightTooltip;
+  } else if (tooltipPosition === tooltipPositions.BOTTOM_LEFT) {
+    const tooltipPointing = Math.min(messagePosition.bottom, containerHeight);
+    style = {
+      left: messagePosition.left,
+      top: tooltipPointing + sizeOfTooltipArrow,
+    };
+    className = css.messageBottomLeftTooltip;
+  } else if (tooltipPosition === tooltipPositions.BOTTOM_RIGHT) {
+    const tooltipPointing = Math.min(messagePosition.bottom, containerHeight);
+    style = {
+      right: containerWidth - messagePosition.right,
+      top: tooltipPointing + sizeOfTooltipArrow,
+    };
+    className = css.messageBottomRightTooltip;
+    console.log(`container height:${containerHeight}`);
+  }
+  invariant(
+    className && style,
+    `${tooltipPosition} is not valid for timestamp tooltip`,
+  );
+  return { className, style };
+}
+
+export default MessageTimestampTooltip;
diff --git a/web/chat/message-tooltip.css b/web/chat/message-tooltip.css
--- a/web/chat/message-tooltip.css
+++ b/web/chat/message-tooltip.css
@@ -9,24 +9,6 @@
   width: fit-content;
 }
 
-div.timestampContainer {
-  display: flex;
-  flex-direction: row;
-  align-items: center;
-  justify-content: center;
-  padding: 0 6px;
-  margin-top: 6px;
-  background-color: var(--message-action-tooltip-bg);
-  border-radius: 8px;
-  color: var(--tool-tip-color);
-}
-
-div.timestampContainer p {
-  white-space: nowrap;
-  padding: 5px;
-  font-size: var(--s-font-14);
-}
-
 div.messageActionButtons {
   display: flex;
   font-size: 16px;
diff --git a/web/chat/message-tooltip.react.js b/web/chat/message-tooltip.react.js
--- a/web/chat/message-tooltip.react.js
+++ b/web/chat/message-tooltip.react.js
@@ -7,10 +7,8 @@
 import type { ChatMessageInfoItem } from 'lib/selectors/chat-selectors';
 import { useSidebarExistsOrCanBeCreated } from 'lib/shared/thread-utils';
 import type { ThreadInfo } from 'lib/types/thread-types';
-import { longAbsoluteDate } from 'lib/utils/date-utils';
 
 import type { InputState } from '../input/input-state';
-import { useSelector } from '../redux/redux-utils';
 import {
   useOnClickThread,
   useOnClickPendingSidebar,
@@ -190,12 +188,6 @@
     );
   }
 
-  const timezone = useSelector(state => state.timeZone);
-  const timestampText = React.useMemo(
-    () => longAbsoluteDate(messageInfo.time, timezone),
-    [messageInfo.time, timezone],
-  );
-
   const { isViewer } = messageInfo.creator;
   const messageActionButtonsContainerClassName = classNames({
     [css.messageActionContainer]: true,
@@ -209,9 +201,6 @@
         {sidebarButton}
         {replyButton}
       </div>
-      <div className={css.timestampContainer}>
-        <p>{timestampText}</p>
-      </div>
     </div>
   );
 }