diff --git a/resources/qml/ForwardCompleter.qml b/resources/qml/ForwardCompleter.qml
new file mode 100644
index 0000000000000000000000000000000000000000..2b5e6dfe742adf107a0b0e56d076c7abaeef698e
--- /dev/null
+++ b/resources/qml/ForwardCompleter.qml
@@ -0,0 +1,81 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+import QtQuick 2.9
+import QtQuick.Controls 2.3
+import im.nheko 1.0
+
+Popup {
+    id: forwardMessagePopup
+    x: 400
+    y: 400
+
+    width: 200
+
+    property var mid
+
+    onOpened: {
+        completerPopup.open();
+        roomTextInput.forceActiveFocus();
+    }
+
+    onClosed: {
+        completerPopup.close();
+    }
+
+    background: Rectangle {
+        border.color: "#444"
+    }
+
+    function setMessageEventId(mid_in) {
+        mid = mid_in;
+    }
+
+    MatrixTextField {
+        id: roomTextInput
+
+        width: forwardMessagePopup.width - forwardMessagePopup.leftPadding * 2
+
+        color: colors.text
+        onTextEdited: {
+            completerPopup.completer.searchString = text;
+        }
+        Keys.onPressed: {
+            if (event.key == Qt.Key_Up && completerPopup.opened) {
+                event.accepted = true;
+                completerPopup.up();
+            } else if (event.key == Qt.Key_Down && completerPopup.opened) {
+                event.accepted = true;
+                completerPopup.down();
+            } else if (event.matches(StandardKey.InsertParagraphSeparator)) {
+                completerPopup.finishCompletion();
+                event.accepted = true;
+            }
+        }
+    }
+
+    Completer {
+        id: completerPopup
+
+        y: roomTextInput.height + roomTextInput.bottomPadding
+        width: forwardMessagePopup.width - forwardMessagePopup.leftPadding * 2
+        completerName: "room"
+        avatarHeight: 24
+        avatarWidth: 24
+        bottomToTop: false
+        closePolicy: Popup.NoAutoClose
+    }
+
+    Connections {
+        onCompletionSelected: {
+            TimelineManager.timeline.forwardMessage(messageContextMenu.eventId, id);
+            forwardMessagePopup.close();
+        }
+        onCountChanged: {
+            if (completerPopup.count > 0 && (completerPopup.currentIndex < 0 || completerPopup.currentIndex >= completerPopup.count))
+                completerPopup.currentIndex = 0;
+        }
+        target: completerPopup
+    }
+}
\ No newline at end of file
diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml
index 2b6a8f267f83d1a91993fef357fb0310e810539f..6c75eb742c1fd7cfef3b34c1d61e7155198311aa 100644
--- a/resources/qml/TimelineView.qml
+++ b/resources/qml/TimelineView.qml
@@ -80,74 +80,9 @@ Page {
     }
 
     Component {
-        id: forwardCompleter
+        id: forwardCompleterComponent
 
-        Popup {
-            id: forwardMessagePopup
-            x: 400
-            y: 400
-
-            property var mid
-
-            onOpened: {
-                completerPopup.open();
-                roomTextInput.forceActiveFocus();
-            }
-
-            background: Rectangle {
-                border.color: "#444"
-            }
-
-            function setMessageEventId(mid_in) {
-                mid = mid_in;
-            }
-
-            MatrixTextField {
-                id: roomTextInput
-
-                width: 100
-
-                color: colors.text
-                onTextEdited: {
-                    completerPopup.completer.searchString = text;
-                }
-                Keys.onPressed: {
-                    if (event.key == Qt.Key_Up && completerPopup.opened) {
-                        event.accepted = true;
-                        completerPopup.up();
-                    } else if (event.key == Qt.Key_Down && completerPopup.opened) {
-                        event.accepted = true;
-                        completerPopup.down();
-                    } else if (event.matches(StandardKey.InsertParagraphSeparator)) {
-                        completerPopup.finishCompletion();
-                        event.accepted = true;
-                    }
-                }
-            }
-
-            Completer {
-                id: completerPopup
-
-                y: 50
-                width: 100
-                completerName: "room"
-                avatarHeight: 24
-                avatarWidth: 24
-                bottomToTop: false
-                closePolicy: Popup.NoAutoClose
-            }
-
-            Connections {
-                onCompletionSelected: {
-                    TimelineManager.timeline.forwardMessage(messageContextMenu.eventId, id);
-                    forwardMessagePopup.close();
-                }
-                onCountChanged: {
-                    if (completerPopup.count > 0 && (completerPopup.currentIndex < 0 || completerPopup.currentIndex >= completerPopup.count))
-                        completerPopup.currentIndex = 0;
-                }
-                target: completerPopup
-            }
+        ForwardCompleter {
         }
     }
 
@@ -208,7 +143,7 @@ Page {
         Platform.MenuItem {
             text: qsTr("Forward")
             onTriggered: {
-                var forwardMess = forwardCompleter.createObject(timelineRoot);
+                var forwardMess = forwardCompleterComponent.createObject(timelineRoot);
                 forwardMess.open();
                 forwardMess.setMessageEventId(messageContextMenu.eventId)
             }
diff --git a/resources/res.qrc b/resources/res.qrc
index 328f65cae6f22438abff27ff48b3f01e9dbbfc3d..304493b6d1fa87d0a759cbaf25f80695899619f8 100644
--- a/resources/res.qrc
+++ b/resources/res.qrc
@@ -142,6 +142,7 @@
         <file>qml/TimelineRow.qml</file>
         <file>qml/TopBar.qml</file>
         <file>qml/QuickSwitcher.qml</file>
+        <file>qml/ForwardCompleter.qml</file>
         <file>qml/TypingIndicator.qml</file>
         <file>qml/RoomSettings.qml</file>
         <file>qml/emoji/EmojiButton.qml</file>