diff --git a/resources/qml/Completer.qml b/resources/qml/Completer.qml
index 2fb083e8afb9fd30edc79d6bf2c862e213734db8..7c357629818a2dc20ec958310a3f68ab0fc80a94 100644
--- a/resources/qml/Completer.qml
+++ b/resources/qml/Completer.qml
@@ -3,9 +3,9 @@
 // SPDX-License-Identifier: GPL-3.0-or-later
 
 import "./ui"
-import QtQuick 2.9
-import QtQuick.Controls 2.3
-import QtQuick.Layouts 1.2
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+import QtQuick.Layouts 1.15
 import im.nheko 1.0
 
 Popup {
@@ -77,8 +77,12 @@ Popup {
     }
     padding: 1
     onAboutToShow: currentIndex = -1
-    // height: listView.contentHeight + 2 // + 2 for the padding on top and bottom
-    height: Math.min(listView.contentHeight + 2, 7*popup.avatarHeight + 2)
+    // If we have fewer than 7 items, just use the list view's content height.  
+    // Otherwise, we want to show 7 items.  Each item consists of row spacing between rows, row margins
+    // on each side of a row, 1px of padding above the first item and below the last item, and nominally
+    // some kind of content height.  avatarHeight is used for just about every delegate, so we're using
+    // that until we find something better.  Put is all together and you have the formula below!
+    height: Math.min(listView.contentHeight + 2, 6*rowSpacing + 7*(popup.avatarHeight + 2*rowMargin) + 2)
 
     ListView {
         id: listView
@@ -90,6 +94,7 @@ Popup {
             enabled: !Settings.mobileMode
         }
 
+        reuseItems: true
         anchors.fill: parent
         implicitWidth: fullWidth ? parent.width : contentItem.childrenRect.width
         model: completer
@@ -102,27 +107,24 @@ Popup {
             property variant modelData: model
 
             color: model.index == popup.currentIndex ? Nheko.colors.highlight : Nheko.colors.base
-            height: chooser.childrenRect.height + 2 * popup.rowMargin
-            implicitWidth: fullWidth ? popup.width : chooser.childrenRect.width + 4
-
-            MouseArea {
-                id: mouseArea
-
-                anchors.fill: parent
-                hoverEnabled: true
-                onPositionChanged: popup.currentIndex = model.index
-                onClicked: {
-                    popup.completionClicked(completer.completionAt(model.index));
-                    if (popup.completerName == "room")
-                        popup.completionSelected(model.roomid);
-
-                }
-
-                Ripple {
-                    rippleTarget: mouseArea
-                    color: Qt.rgba(Nheko.colors.base.r, Nheko.colors.base.g, Nheko.colors.base.b, 0.5)
+            height: chooser.child.implicitHeight + 2 * popup.rowMargin
+            implicitWidth: fullWidth ? popup.contentWidth : chooser.child.implicitWidth + 4
+            border.color: 'orange'
+            border.width: 1
+
+            HoverHandler {
+                id: hover
+                onHoveredChanged: {
+                    if (hovered) popup.currentIndex = model.index;
                 }
+            }
 
+            TapHandler {
+                onSingleTapped: {
+                     popup.completionClicked(completer.completionAt(model.index));
+                     if (popup.completerName == "room")
+                         popup.completionSelected(model.roomid);
+                 }
             }
 
             DelegateChooser {
@@ -131,6 +133,7 @@ Popup {
                 roleValue: popup.completerName
                 anchors.fill: parent
                 anchors.margins: popup.rowMargin
+                enabled: false
 
                 DelegateChoice {
                     roleValue: "user"