diff --git a/resources/qml/TimelineRow.qml b/resources/qml/TimelineRow.qml
index dd1b3a0f8503f283a4cb2f15844039b4024d0f2f..1d9a036a4049d54e174bb4a26742337962b9cf37 100644
--- a/resources/qml/TimelineRow.qml
+++ b/resources/qml/TimelineRow.qml
@@ -71,27 +71,39 @@ Item {
         gesturePolicy: TapHandler.ReleaseWithinBounds
     }
 
-    RowLayout {
+    Item {
         id: row
 
         anchors.rightMargin: 1
         anchors.leftMargin: Nheko.avatarSize + 16
         anchors.left: parent.left
         anchors.right: parent.right
-
-        Column {
-            Layout.fillWidth: true
-            Layout.alignment: Qt.AlignTop
-            spacing: 4
-            Layout.topMargin: 1
-            Layout.bottomMargin: 1
+        height: msg.height+reactionRow.height+2
+        GridLayout {
+            id: msg
+            anchors {
+                right: parent.right
+                left: parent.left
+                top: parent.top
+                topMargin: 1
+                bottomMargin: 1
+            }
+            rowSpacing: 0
+            columnSpacing: 0
+            columns: 2
+            rows: 2
 
             // fancy reply, if this is a reply
             Reply {
+                Layout.row: 0
+                Layout.column: 0
+                Layout.fillWidth: true
+                Layout.margins: 0
+                id: reply
+
                 function fromModel(role) {
                     return replyTo != "" ? room.dataById(replyTo, role, r.eventId) : null;
                 }
-
                 visible: replyTo
                 userColor: r.relatedEventCacheBuster, TimelineManager.userColor(userId, Nheko.colors.base)
                 blurhash: r.relatedEventCacheBuster, fromModel(Room.Blurhash) ?? ""
@@ -118,9 +130,12 @@ Item {
 
             // actual message content
             MessageDelegate {
+                Layout.row: 1
+                Layout.column: 0
+                Layout.fillWidth: true
+                Layout.margins: 2
                 id: contentItem
 
-                width: parent.width
                 blurhash: r.blurhash
                 body: r.body
                 formattedBody: r.formattedBody
@@ -144,67 +159,76 @@ Item {
                 isReply: false
             }
 
-            Reactions {
-                id: reactionRow
+            RowLayout {
+                Layout.column: 1
+                Layout.row: 0
+                Layout.rowSpan: 2
+                Layout.alignment: Qt.AlignTop | Qt.AlignRight
+
+                StatusIndicator {
+                    Layout.alignment: Qt.AlignRight | Qt.AlignTop
+                    Layout.preferredHeight: 16
+                    width: 16
+                    status: r.status
+                    eventId: r.eventId
+                }
 
-                reactions: r.reactions
-                eventId: r.eventId
-            }
+                Image {
+                    visible: isEdited || eventId == chat.model.edit
+                    Layout.alignment: Qt.AlignRight | Qt.AlignTop
+                    Layout.preferredHeight: 16
+                    Layout.preferredWidth: 16
+                    height: 16
+                    width: 16
+                    sourceSize.width: 16 * Screen.devicePixelRatio
+                    sourceSize.height: 16 * Screen.devicePixelRatio
+                    source: "image://colorimage/:/icons/icons/ui/edit.svg?" + ((eventId == chat.model.edit) ? Nheko.colors.highlight : Nheko.colors.buttonText)
+                    ToolTip.visible: editHovered.hovered
+                    ToolTip.delay: Nheko.tooltipDelay
+                    ToolTip.text: qsTr("Edited")
+
+                    HoverHandler {
+                        id: editHovered
+                    }
 
-        }
+                }
 
-        StatusIndicator {
-            Layout.alignment: Qt.AlignRight | Qt.AlignTop
-            Layout.preferredHeight: 16
-            width: 16
-            status: r.status
-            eventId: r.eventId
-        }
+                EncryptionIndicator {
+                    visible: room.isEncrypted
+                    encrypted: isEncrypted
+                    trust: trustlevel
+                    Layout.alignment: Qt.AlignRight | Qt.AlignTop
+                    Layout.preferredHeight: 16
+                    Layout.preferredWidth: 16
+                }
 
-        Image {
-            visible: isEdited || eventId == chat.model.edit
-            Layout.alignment: Qt.AlignRight | Qt.AlignTop
-            Layout.preferredHeight: 16
-            Layout.preferredWidth: 16
-            height: 16
-            width: 16
-            sourceSize.width: 16 * Screen.devicePixelRatio
-            sourceSize.height: 16 * Screen.devicePixelRatio
-            source: "image://colorimage/:/icons/icons/ui/edit.svg?" + ((eventId == chat.model.edit) ? Nheko.colors.highlight : Nheko.colors.buttonText)
-            ToolTip.visible: editHovered.hovered
-            ToolTip.delay: Nheko.tooltipDelay
-            ToolTip.text: qsTr("Edited")
-
-            HoverHandler {
-                id: editHovered
-            }
+                Label {
+                    Layout.alignment: Qt.AlignRight | Qt.AlignTop
+                    text: timestamp.toLocaleTimeString(Locale.ShortFormat)
+                    width: Math.max(implicitWidth, text.length * fontMetrics.maximumCharacterWidth)
+                    color: Nheko.inactiveColors.text
+                    ToolTip.visible: ma.hovered
+                    ToolTip.delay: Nheko.tooltipDelay
+                    ToolTip.text: Qt.formatDateTime(timestamp, Qt.DefaultLocaleLongDate)
 
-        }
+                    HoverHandler {
+                        id: ma
+                    }
 
-        EncryptionIndicator {
-            visible: room.isEncrypted
-            encrypted: isEncrypted
-            trust: trustlevel
-            Layout.alignment: Qt.AlignRight | Qt.AlignTop
-            Layout.preferredHeight: 16
-            Layout.preferredWidth: 16
+                }
+            }
         }
 
-        Label {
-            Layout.alignment: Qt.AlignRight | Qt.AlignTop
-            text: timestamp.toLocaleTimeString(Locale.ShortFormat)
-            width: Math.max(implicitWidth, text.length * fontMetrics.maximumCharacterWidth)
-            color: Nheko.inactiveColors.text
-            ToolTip.visible: ma.hovered
-            ToolTip.delay: Nheko.tooltipDelay
-            ToolTip.text: Qt.formatDateTime(timestamp, Qt.DefaultLocaleLongDate)
-
-            HoverHandler {
-                id: ma
+        Reactions {
+            anchors {
+                top: msg.bottom
+                left: parent.left
             }
 
-        }
+            id: reactionRow
 
+            reactions: r.reactions
+            eventId: r.eventId
+        }
     }
-
 }
diff --git a/resources/qml/delegates/MessageDelegate.qml b/resources/qml/delegates/MessageDelegate.qml
index c0266c2c71face4cf78499c84b06d2b2c811d262..ad6e7580d043383ff6da06df0062d7f4b273ef57 100644
--- a/resources/qml/delegates/MessageDelegate.qml
+++ b/resources/qml/delegates/MessageDelegate.qml
@@ -13,7 +13,7 @@ Item {
 
     required property bool isReply
     property alias child: chooser.child
-    property real implicitWidth: (chooser.child && chooser.child.implicitWidth) ? chooser.child.implicitWidth : width
+//    property real implicitWidth: (chooser.child && chooser.child.implicitWidth) ? chooser.child.implicitWidth : width
     required property double proportionalHeight
     required property int type
     required property string typeString
@@ -35,14 +35,17 @@ Item {
     required property int encryptionError
     required property int relatedEventCacheBuster
 
-    height: chooser.child ? chooser.child.height : Nheko.paddingLarge
+    Layout.preferredHeight: chooser.child ? chooser.child.height : Nheko.paddingLarge
 
     DelegateChooser {
         id: chooser
 
         //role: "type" //< not supported in our custom implementation, have to use roleValue
         roleValue: type
-        anchors.fill: parent
+        //anchors.fill: parent
+
+        anchors.left: parent.left
+        anchors.right: parent.right
 
         DelegateChoice {
             roleValue: MtxEvent.UnknownMessage
diff --git a/resources/qml/delegates/Placeholder.qml b/resources/qml/delegates/Placeholder.qml
index 19e48393ba2dd22077b7d32f395f849e2edbbb67..f63e62f57c98fcb9b4e794bf6772561e9b9d84a9 100644
--- a/resources/qml/delegates/Placeholder.qml
+++ b/resources/qml/delegates/Placeholder.qml
@@ -10,6 +10,6 @@ MatrixText {
     required property string typeString
 
     text: qsTr("unimplemented event: ") + typeString
-    width: parent.width
+//    width: parent.width
     color: Nheko.inactiveColors.text
 }
diff --git a/resources/qml/delegates/Reply.qml b/resources/qml/delegates/Reply.qml
index d148f85810a0363a77aeea499fb1ad573c3c735b..efa959a0f83be60f02c74f1615ff9436e5f007d7 100644
--- a/resources/qml/delegates/Reply.qml
+++ b/resources/qml/delegates/Reply.qml
@@ -35,7 +35,7 @@ Item {
     property int encryptionError
     property int relatedEventCacheBuster
 
-    width: parent.width
+    Layout.preferredHeight: replyContainer.height
     height: replyContainer.height
 
     CursorShape {
@@ -52,12 +52,12 @@ Item {
         color: TimelineManager.userColor(userId, Nheko.colors.base)
     }
 
-    Column {
+    ColumnLayout {
         id: replyContainer
 
         anchors.left: colorLine.right
-        anchors.leftMargin: 4
         width: parent.width - 8
+        spacing: 0
 
         TapHandler {
             acceptedButtons: Qt.LeftButton
@@ -80,6 +80,7 @@ Item {
         }
 
         Text {
+            Layout.leftMargin: 4
             id: userName_
 
             text: TimelineManager.escapeEmoji(userName)
@@ -94,8 +95,8 @@ Item {
         }
 
         MessageDelegate {
+            Layout.leftMargin: 4
             id: reply
-
             blurhash: r.blurhash
             body: r.body
             formattedBody: r.formattedBody
@@ -118,7 +119,7 @@ Item {
             encryptionError: r.encryptionError
             // This is disabled so that left clicking the reply goes to its location
             enabled: false
-            width: parent.width
+            Layout.fillWidth: true
             isReply: true
         }
 
@@ -128,8 +129,7 @@ Item {
         id: backgroundItem
 
         z: -1
-        height: replyContainer.height
-        width: Math.min(Math.max(reply.implicitWidth, userName_.implicitWidth) + 8 + 4, parent.width)
+        anchors.fill: replyContainer
         color: Qt.rgba(userColor.r, userColor.g, userColor.b, 0.1)
     }
 
diff --git a/resources/qml/delegates/TextMessage.qml b/resources/qml/delegates/TextMessage.qml
index eea8cd1e4b7d3bbac79a2b73b9e93ce34af9d326..c9b8a882064cf163efbef2945df3f538c228aa69 100644
--- a/resources/qml/delegates/TextMessage.qml
+++ b/resources/qml/delegates/TextMessage.qml
@@ -33,8 +33,8 @@ MatrixText {
     blockquote { margin-left: 1em; }
     </style>
     " + formatted.replace("<pre>", "<pre style='white-space: pre-wrap; background-color: " + Nheko.colors.alternateBase + "'>").replace("<del>", "<s>").replace("</del>", "</s>").replace("<strike>", "<s>").replace("</strike>", "</s>")
-    width: parent.width
-    height: isReply ? Math.round(Math.min(timelineView.height / 8, implicitHeight)) : undefined
+//    width: parent.width
+    //height: isReply ? Math.round(Math.min(timelineView.height / 8, implicitHeight)) : undefined
     clip: isReply
     selectByMouse: !Settings.mobileMode && !isReply
     font.pointSize: (Settings.enlargeEmojiOnlyMessages && isOnlyEmoji > 0 && isOnlyEmoji < 4) ? Settings.fontSize * 3 : Settings.fontSize