diff --git a/res/css/views/rooms/_EventBubbleTile.scss b/res/css/views/rooms/_EventBubbleTile.scss
index 8ab391facf..ef988eec27 100644
--- a/res/css/views/rooms/_EventBubbleTile.scss
+++ b/res/css/views/rooms/_EventBubbleTile.scss
@@ -42,6 +42,10 @@ limitations under the License.
         width: fit-content;
     }
 
+    .mx_EventTile_content {
+        margin-right: 0;
+    }
+
     &.mx_EventTile_continuation {
         margin-top: 2px;
     }
@@ -419,6 +423,22 @@ limitations under the License.
 
 .mx_EventTile.mx_EventTile_noBubble[data-layout=bubble] {
     --backgroundColor: transparent;
+
+    .mx_EventTile_line.mx_EventTile_emote {
+        padding-right: 60px; // align with bubbles text
+        font-style: italic;
+
+        > a { // timestamp anchor wrapper
+            align-self: center;
+            bottom: unset;
+            top: unset;
+            font-style: normal; // undo italic above
+        }
+
+        .mx_MEmoteBody {
+            padding: 4px 0;
+        }
+    }
 }
 
 .mx_EventTile.mx_EventTile_bubbleContainer[data-layout=bubble],
diff --git a/src/components/views/rooms/EventTile.tsx b/src/components/views/rooms/EventTile.tsx
index 89d6e1e6d7..446245108e 100644
--- a/src/components/views/rooms/EventTile.tsx
+++ b/src/components/views/rooms/EventTile.tsx
@@ -1122,6 +1122,10 @@ export default class EventTile extends React.Component<IProps, IState> {
         const lineClasses = classNames("mx_EventTile_line", {
             mx_EventTile_mediaLine: isProbablyMedia,
             mx_EventTile_sticker: this.props.mxEvent.getType() === EventType.Sticker,
+            mx_EventTile_emote: (
+                this.props.mxEvent.getType() === EventType.RoomMessage &&
+                this.props.mxEvent.getContent().msgtype === MsgType.Emote
+            ),
         });
 
         const isSending = (['sending', 'queued', 'encrypting'].indexOf(this.props.eventSendStatus) !== -1);
diff --git a/src/utils/EventUtils.ts b/src/utils/EventUtils.ts
index 187ee23784..97ad4e1040 100644
--- a/src/utils/EventUtils.ts
+++ b/src/utils/EventUtils.ts
@@ -213,7 +213,7 @@ export function getEventDisplayInfo(mxEvent: MatrixEvent): {
     // Info messages are basically information about commands processed on a room
     let isBubbleMessage = (
         eventType.startsWith("m.key.verification") ||
-        (eventType === EventType.RoomMessage && msgtype && msgtype.startsWith("m.key.verification")) ||
+        (eventType === EventType.RoomMessage && msgtype?.startsWith("m.key.verification")) ||
         (eventType === EventType.RoomCreate) ||
         (eventType === EventType.RoomEncryption) ||
         (tileHandler === "messages.MJitsiWidgetEvent")
@@ -232,6 +232,7 @@ export function getEventDisplayInfo(mxEvent: MatrixEvent): {
     );
     // Some non-info messages want to be rendered in the appropriate bubble column but without the bubble background
     const noBubbleEvent = (
+        (eventType === EventType.RoomMessage && msgtype === MsgType.Emote) ||
         M_POLL_START.matches(eventType) ||
         LOCATION_EVENT_TYPE.matches(eventType) ||
         (