diff --git a/CMakeLists.txt b/CMakeLists.txt
index 09eea0716d6dc4f590cbf842987e1cab88080624..4d5aff7aa49e9deac2c447c1912569f528f37c55 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -179,7 +179,6 @@ set(SRC_FILES
     src/dialogs/LeaveRoom.cpp
     src/dialogs/Logout.cpp
     src/dialogs/UserProfile.cpp
-    src/dialogs/UserMentions.cpp
     src/dialogs/ReadReceipts.cpp
     src/dialogs/ReCaptcha.cpp
     src/dialogs/RoomSettings.cpp
@@ -241,13 +240,13 @@ set(SRC_FILES
     src/popups/SuggestionsPopup.cpp
     src/popups/PopupItem.cpp
     src/popups/ReplyPopup.cpp
+    src/popups/UserMentions.cpp
     src/TextInputWidget.cpp
     src/TopRoomBar.cpp
     src/TrayIcon.cpp
     src/TypingDisplay.cpp
     src/Utils.cpp
     src/UserInfoWidget.cpp
-    src/UserMentionsWidget.cpp
     src/UserSettingsPage.cpp
     src/WelcomePage.cpp
     src/main.cpp
@@ -321,7 +320,6 @@ qt5_wrap_cpp(MOC_HEADERS
     src/dialogs/MemberList.h
     src/dialogs/LeaveRoom.h
     src/dialogs/Logout.h
-    src/dialogs/UserMentions.h
     src/dialogs/UserProfile.h
     src/dialogs/RawMessage.h
     src/dialogs/ReadReceipts.h
@@ -383,12 +381,12 @@ qt5_wrap_cpp(MOC_HEADERS
     src/popups/SuggestionsPopup.h
     src/popups/ReplyPopup.h
     src/popups/PopupItem.h
+    src/popups/UserMentions.h
     src/TextInputWidget.h
     src/TopRoomBar.h
     src/TrayIcon.h
     src/TypingDisplay.h
     src/UserInfoWidget.h
-    src/UserMentionsWidget.h
     src/UserSettingsPage.h
     src/WelcomePage.h
 )
diff --git a/src/Cache.cpp b/src/Cache.cpp
index 9bf3b5b02767c13932d4945ec8bfabe68afa6582..5ccf92914b9642172ab7a30aa230306ec0a0b6c1 100644
--- a/src/Cache.cpp
+++ b/src/Cache.cpp
@@ -1232,6 +1232,28 @@ Cache::roomMessages()
         return msgs;
 }
 
+std::map<QString, mtx::responses::Notifications>
+Cache::getTimelineMentions()
+{
+        // TODO: Should be read-only, but getMentionsDb will attempt to create a DB
+        // if it doesn't exist, throwing an error.
+        auto txn = lmdb::txn::begin(env_, nullptr);
+
+        std::map<QString, mtx::responses::Notifications> notifs;
+
+        auto room_ids = getRoomIds(txn);
+
+        for (const auto &room_id : room_ids) {
+                auto roomNotifs = getTimelineMentionsForRoom(txn, room_id);
+                notifs.emplace(QString::fromStdString(room_id), roomNotifs);
+        }
+
+        txn.commit();
+
+        return notifs;
+}
+
+
 mtx::responses::Timeline
 Cache::getTimelineMessages(lmdb::txn &txn, const std::string &room_id)
 {
@@ -1934,11 +1956,16 @@ Cache::saveTimelineMessages(lmdb::txn &txn,
                               lmdb::val(obj.dump()));
         }
 }
+
 mtx::responses::Notifications
-Cache::getTimelineMentions(lmdb::txn &txn, const std::string &room_id)
+Cache::getTimelineMentionsForRoom(lmdb::txn &txn, const std::string &room_id)
 {
         auto db = getMentionsDb(txn, room_id);
 
+        if (db.size(txn) == 0) {
+                return mtx::responses::Notifications{};
+        }
+
         mtx::responses::Notifications notif;
         std::string event_id, msg;
 
@@ -1961,29 +1988,52 @@ Cache::getTimelineMentions(lmdb::txn &txn, const std::string &room_id)
 
         return notif;
 }
+
+//! Add all notifications containing a user mention to the db.
+void
+Cache::saveTimelineMentions(const mtx::responses::Notifications &res)
+{
+        QMap<std::string, QList<mtx::responses::Notification>> notifsByRoom;
+
+        // Sort into room-specific 'buckets'
+        for (const auto &notif : res.notifications) {
+                notifsByRoom[notif.room_id].push_back(notif);
+        }
+
+        auto txn = lmdb::txn::begin(env_);
+        // Insert the entire set of mentions for each room at a time.
+        for (const auto &room : notifsByRoom.keys()) {
+                nhlog::db()->debug("Storing notifications for " + room);
+                saveTimelineMentions(txn, room, notifsByRoom[room]);
+        }
+
+        txn.commit();
+}
+
 void
 Cache::saveTimelineMentions(lmdb::txn &txn,
                             const std::string &room_id,
-                            const mtx::responses::Notifications &res)
+                            const QList<mtx::responses::Notification> &res)
 {
         auto db = getMentionsDb(txn, room_id);
 
         using namespace mtx::events;
         using namespace mtx::events::state;
 
-        for (const auto &n : res.notifications) {
-                const auto event_id = utils::event_id(n.event);
+        int i = 0;
+        for (const auto &notif : res) {
+                nhlog::db()->debug("Storing notification " + std::to_string(i++) + " for room " + room_id);
+                const auto event_id = utils::event_id(notif.event);
 
                 // double check that we have the correct room_id...
-                if (room_id.compare(n.room_id) != 0)
-                        continue;
+                if (room_id.compare(notif.room_id) != 0) {
+                        return;
+                }
 
                 json obj = json::object();
 
                 lmdb::dbi_put(txn, db, lmdb::val(event_id), lmdb::val(obj.dump()));
         }
-
-        txn.commit();
 }
 
 void
diff --git a/src/Cache.h b/src/Cache.h
index 5971df6635a4a49d75699be9a4af7056683056b6..07ccf79079898f1efa37f6fe85e0f58d5ca39355 100644
--- a/src/Cache.h
+++ b/src/Cache.h
@@ -323,6 +323,8 @@ public:
 
         std::map<QString, mtx::responses::Timeline> roomMessages();
 
+        std::map<QString, mtx::responses::Notifications> getTimelineMentions();
+
         //! Retrieve all the user ids from a room.
         std::vector<std::string> roomMembers(const std::string &room_id);
 
@@ -402,13 +404,8 @@ public:
         //! Check if we have sent a desktop notification for the given event id.
         bool isNotificationSent(const std::string &event_id);
 
-        //! Add a notification containing a user mention to the db.
-        void saveTimelineMentions(lmdb::txn &txn,
-                                  const std::string &room_id,
-                                  const mtx::responses::Notifications &res);
-        //! Get timeline items that a user was mentions in
-        mtx::responses::Notifications getTimelineMentions(lmdb::txn &txn,
-                                                          const std::string &room_id);
+        //! Add all notifications containing a user mention to the db.
+        void saveTimelineMentions(const mtx::responses::Notifications &res);
 
         //! Remove old unused data.
         void deleteOldMessages();
@@ -478,6 +475,15 @@ private:
                         lmdb::dbi &membersdb,
                         const mtx::responses::InvitedRoom &room);
 
+        //! Add a notification containing a user mention to the db.
+        void saveTimelineMentions(lmdb::txn &txn,
+                                  const std::string &room_id,
+                                  const QList<mtx::responses::Notification> &res);
+
+        //! Get timeline items that a user was mentions in for a given room
+        mtx::responses::Notifications getTimelineMentionsForRoom(lmdb::txn &txn,
+                                                          const std::string &room_id);
+
         QString getInviteRoomName(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb);
         QString getInviteRoomTopic(lmdb::txn &txn, lmdb::dbi &statesdb);
         QString getInviteRoomAvatarUrl(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb);
diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp
index ca18d810bf2503c934d901cf063c8f06b6ec88a8..2a02e7400da732c21444e8d82610f6644203134c 100644
--- a/src/ChatPage.cpp
+++ b/src/ChatPage.cpp
@@ -35,7 +35,6 @@
 #include "TopRoomBar.h"
 #include "TypingDisplay.h"
 #include "UserInfoWidget.h"
-#include "UserMentionsWidget.h"
 #include "UserSettingsPage.h"
 #include "Utils.h"
 #include "ui/OverlayModal.h"
@@ -44,7 +43,7 @@
 #include "notifications/Manager.h"
 
 #include "dialogs/ReadReceipts.h"
-#include "dialogs/UserMentions.h"
+#include "popups/UserMentions.h"
 #include "timeline/TimelineViewManager.h"
 
 // TODO: Needs to be updated with an actual secret.
@@ -91,7 +90,7 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
         connect(sidebarActions_, &SideBarActions::createRoom, this, &ChatPage::createRoom);
 
         user_info_widget_ = new UserInfoWidget(sideBar_);
-        // user_mentions_widget_ = new UserMentionsWidget(top_bar_);
+        user_mentions_popup_ = new popups::UserMentions();
         room_list_ = new RoomList(sideBar_);
         connect(room_list_, &RoomList::joinRoom, this, &ChatPage::joinRoom);
 
@@ -518,8 +517,17 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
 
         connect(this, &ChatPage::leftRoom, this, &ChatPage::removeRoom);
         connect(this, &ChatPage::notificationsRetrieved, this, &ChatPage::sendDesktopNotifications);
-        connect(
-          this, &ChatPage::highlightedNotifsRetrieved, this, &ChatPage::showNotificationsDialog);
+        connect(this,
+                &ChatPage::highlightedNotifsRetrieved,
+                this,
+                [this](const mtx::responses::Notifications &notif, const QPoint &widgetPos) {
+                        try {
+                                cache::client()->saveTimelineMentions(notif);
+                        } catch (const lmdb::error &e) {
+                                nhlog::db()->error("failed to save mentions: {}", e.what());
+                        }
+                        showNotificationsDialog(notif, widgetPos);
+                });
 
         connect(communitiesList_,
                 &CommunitiesList::communityChanged,
@@ -558,6 +566,10 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
                 &ChatPage::initializeEmptyViews,
                 view_manager_,
                 &TimelineViewManager::initWithMessages);
+        connect(this,
+                &ChatPage::initializeMentions,
+                user_mentions_popup_,
+                &popups::UserMentions::initializeMentions);
         connect(this, &ChatPage::syncUI, this, [this](const mtx::responses::Rooms &rooms) {
                 try {
                         room_list_->cleanupInvites(cache::client()->invites());
@@ -830,6 +842,7 @@ ChatPage::loadStateFromCache()
 
                         emit initializeEmptyViews(cache::client()->roomMessages());
                         emit initializeRoomList(cache::client()->roomInfo());
+                        emit initializeMentions(cache::client()->getTimelineMentions());
                         emit syncTags(cache::client()->roomInfo().toStdMap());
 
                         cache::client()->calculateRoomReadStatus();
@@ -988,9 +1001,7 @@ ChatPage::sendDesktopNotifications(const mtx::responses::Notifications &res)
 void
 ChatPage::showNotificationsDialog(const mtx::responses::Notifications &res, const QPoint &widgetPos)
 {
-        // TODO: This should NOT BE A DIALOG.  Make the TimelineView support
-        // creating a timeline view from notifications (similarly to how it can show history views)
-        auto notifDialog = new dialogs::UserMentions();
+        auto notifDialog = user_mentions_popup_;
         for (const auto &item : res.notifications) {
                 const auto event_id = QString::fromStdString(utils::event_id(item.event));
 
@@ -1242,6 +1253,8 @@ ChatPage::sendTypingNotifications()
 void
 ChatPage::initialSyncHandler(const mtx::responses::Sync &res, mtx::http::RequestErr err)
 {
+        // TODO: Initial Sync should include mentions as well...
+
         if (err) {
                 const auto error      = QString::fromStdString(err->matrix_error.error);
                 const auto msg        = tr("Please try to login again: %1").arg(error);
diff --git a/src/ChatPage.h b/src/ChatPage.h
index 3c97ba25fc786dc0af0882952a8e55b3cf8c9d5d..87876a09869ea1ed8b00f76d400341d0559d8ff4 100644
--- a/src/ChatPage.h
+++ b/src/ChatPage.h
@@ -19,6 +19,7 @@
 
 #include <atomic>
 #include <boost/variant.hpp>
+#include <mtx/responses.hpp>
 
 #include <QFrame>
 #include <QHBoxLayout>
@@ -33,6 +34,7 @@
 #include "MatrixClient.h"
 #include "Utils.h"
 #include "notifications/Manager.h"
+#include "popups/UserMentions.h"
 
 class OverlayModal;
 class QuickSwitcher;
@@ -44,7 +46,6 @@ class TimelineViewManager;
 class TopRoomBar;
 class TypingDisplay;
 class UserInfoWidget;
-class UserMentionsWidget;
 class UserSettings;
 class NotificationsManager;
 
@@ -139,6 +140,7 @@ signals:
         void initializeRoomList(QMap<QString, RoomInfo>);
         void initializeViews(const mtx::responses::Rooms &rooms);
         void initializeEmptyViews(const std::map<QString, mtx::responses::Timeline> &msgs);
+        void initializeMentions(const std::map<QString, mtx::responses::Notifications> &notifs);
         void syncUI(const mtx::responses::Rooms &rooms);
         void syncRoomlist(const std::map<QString, RoomInfo> &updates);
         void syncTags(const std::map<QString, RoomInfo> &updates);
@@ -242,7 +244,7 @@ private:
 
         UserInfoWidget *user_info_widget_;
 
-        UserMentionsWidget *user_mentions_widget_;
+        popups::UserMentions *user_mentions_popup_;
 
         // Keeps track of the users currently typing on each room.
         std::map<QString, QList<QString>> typingUsers_;
diff --git a/src/UserMentionsWidget.cpp b/src/UserMentionsWidget.cpp
deleted file mode 100644
index a28db930323365ab68e73354250eb3d7e6cd052c..0000000000000000000000000000000000000000
--- a/src/UserMentionsWidget.cpp
+++ /dev/null
@@ -1,309 +0,0 @@
-#include <QDateTime>
-#include <QDebug>
-#include <QMouseEvent>
-#include <QPainter>
-#include <QtGlobal>
-
-#include "MainWindow.h"
-#include "UserMentionsWidget.h"
-#include "Utils.h"
-#include "ui/Ripple.h"
-#include "ui/RippleOverlay.h"
-
-constexpr int MaxUnreadCountDisplayed = 99;
-
-struct WMetrics
-{
-        int maxHeight;
-        int iconSize;
-        int padding;
-        int unit;
-
-        int unreadLineWidth;
-        int unreadLineOffset;
-
-        int inviteBtnX;
-        int inviteBtnY;
-};
-
-WMetrics
-getWMetrics(const QFont &font)
-{
-        WMetrics m;
-
-        const int height = QFontMetrics(font).lineSpacing();
-
-        m.unit             = height;
-        m.maxHeight        = std::ceil((double)height * 3.8);
-        m.iconSize         = std::ceil((double)height * 2.8);
-        m.padding          = std::ceil((double)height / 2.0);
-        m.unreadLineWidth  = m.padding - m.padding / 3;
-        m.unreadLineOffset = m.padding - m.padding / 4;
-
-        m.inviteBtnX = m.iconSize + 2 * m.padding;
-        m.inviteBtnX = m.iconSize / 2.0 + m.padding + m.padding / 3.0;
-
-        return m;
-}
-
-UserMentionsWidget::UserMentionsWidget(QWidget *parent)
-  : QWidget(parent)
-  , isPressed_(false)
-  , unreadMsgCount_(0)
-{
-        init(parent);
-
-        QFont f;
-        f.setPointSizeF(f.pointSizeF());
-
-        const int fontHeight    = QFontMetrics(f).height();
-        const int widgetMargin  = fontHeight / 3;
-        const int contentHeight = fontHeight * 3;
-
-        setFixedHeight(contentHeight + widgetMargin);
-
-        topLayout_ = new QHBoxLayout(this);
-        topLayout_->setSpacing(0);
-        topLayout_->setMargin(widgetMargin);
-}
-
-void
-UserMentionsWidget::init(QWidget *parent)
-{
-        setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
-        setMouseTracking(true);
-        setAttribute(Qt::WA_Hover);
-
-        setFixedHeight(getWMetrics(QFont{}).maxHeight);
-
-        QPainterPath path;
-        path.addRect(0, 0, parent->width(), height());
-
-        ripple_overlay_ = new RippleOverlay(this);
-        ripple_overlay_->setClipPath(path);
-        ripple_overlay_->setClipping(true);
-
-        unreadCountFont_.setPointSizeF(unreadCountFont_.pointSizeF() * 0.8);
-        unreadCountFont_.setBold(true);
-
-        bubbleDiameter_ = QFontMetrics(unreadCountFont_).averageCharWidth() * 3;
-}
-
-// void
-// UserMentionsWidget::resizeEvent(QResizeEvent *event)
-// {
-//         Q_UNUSED(event);
-
-//         const auto sz = utils::calculateSidebarSizes(QFont{});
-
-//         if (width() <= sz.small) {
-//                 topLayout_->setContentsMargins(0, 0, logoutButtonSize_, 0);
-
-//         } else {
-//                 topLayout_->setMargin(5);
-//         }
-
-//         QWidget::resizeEvent(event);
-// }
-
-void
-UserMentionsWidget::setPressedState(bool state)
-{
-        if (isPressed_ != state) {
-                isPressed_ = state;
-                update();
-        }
-}
-
-void
-UserMentionsWidget::resizeEvent(QResizeEvent *)
-{
-        // Update ripple's clipping path.
-        QPainterPath path;
-        path.addRect(0, 0, width(), height());
-
-        const auto sidebarSizes = utils::calculateSidebarSizes(QFont{});
-
-        if (width() > sidebarSizes.small)
-                setToolTip("");
-        else
-                setToolTip("");
-
-        ripple_overlay_->setClipPath(path);
-        ripple_overlay_->setClipping(true);
-}
-
-void
-UserMentionsWidget::mousePressEvent(QMouseEvent *event)
-{
-        if (event->buttons() == Qt::RightButton) {
-                QWidget::mousePressEvent(event);
-                return;
-        }
-
-        emit clicked();
-
-        setPressedState(true);
-
-        // Ripple on mouse position by default.
-        QPoint pos           = event->pos();
-        qreal radiusEndValue = static_cast<qreal>(width()) / 3;
-
-        Ripple *ripple = new Ripple(pos);
-
-        ripple->setRadiusEndValue(radiusEndValue);
-        ripple->setOpacityStartValue(0.15);
-        ripple->setColor(QColor("white"));
-        ripple->radiusAnimation()->setDuration(200);
-        ripple->opacityAnimation()->setDuration(400);
-
-        ripple_overlay_->addRipple(ripple);
-}
-
-void
-UserMentionsWidget::paintEvent(QPaintEvent *event)
-{
-        Q_UNUSED(event);
-
-        QPainter p(this);
-        p.setRenderHint(QPainter::TextAntialiasing);
-        p.setRenderHint(QPainter::SmoothPixmapTransform);
-        p.setRenderHint(QPainter::Antialiasing);
-
-        auto wm = getWMetrics(QFont{});
-
-        QPen titlePen(titleColor_);
-        QPen subtitlePen(subtitleColor_);
-
-        QFontMetrics metrics(QFont{});
-
-        if (isPressed_) {
-                p.fillRect(rect(), highlightedBackgroundColor_);
-                titlePen.setColor(highlightedTitleColor_);
-                subtitlePen.setColor(highlightedSubtitleColor_);
-        } else if (underMouse()) {
-                p.fillRect(rect(), hoverBackgroundColor_);
-                titlePen.setColor(hoverTitleColor_);
-                subtitlePen.setColor(hoverSubtitleColor_);
-        } else {
-                p.fillRect(rect(), backgroundColor_);
-                titlePen.setColor(titleColor_);
-                subtitlePen.setColor(subtitleColor_);
-        }
-
-        // Description line with the default font.
-        int bottom_y = wm.maxHeight - wm.padding - metrics.ascent() / 2;
-
-        const auto sidebarSizes = utils::calculateSidebarSizes(QFont{});
-
-        if (width() > sidebarSizes.small) {
-                QFont headingFont;
-                headingFont.setWeight(QFont::Medium);
-                p.setFont(headingFont);
-                p.setPen(titlePen);
-
-                QFont tsFont;
-                tsFont.setPointSizeF(tsFont.pointSizeF() * 0.9);
-#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
-                const int msgStampWidth = QFontMetrics(tsFont).width("timestamp") + 4;
-#else
-                const int msgStampWidth = QFontMetrics(tsFont).horizontalAdvance("timestamp") + 4;
-#endif
-                // We use the full width of the widget if there is no unread msg bubble.
-                // const int bottomLineWidthLimit = (unreadMsgCount_ > 0) ? msgStampWidth : 0;
-
-                // Name line.
-                QFontMetrics fontNameMetrics(headingFont);
-                int top_y = 2 * wm.padding + fontNameMetrics.ascent() / 2;
-
-                const auto name = metrics.elidedText(
-                  "Mentions",
-                  Qt::ElideRight,
-                  (width() - wm.iconSize - 2 * wm.padding - msgStampWidth) * 0.8);
-                p.drawText(QPoint(2 * wm.padding + wm.iconSize, top_y), name);
-
-                p.setFont(QFont{});
-                p.setPen(subtitlePen);
-
-                // The limit is the space between the end of the avatar and the start of the
-                // timestamp.
-                int usernameLimit =
-                  std::max(0, width() - 3 * wm.padding - msgStampWidth - wm.iconSize - 20);
-                auto userName =
-                  metrics.elidedText("Show Mentioned Messages", Qt::ElideRight, usernameLimit);
-
-                p.setFont(QFont{});
-                p.drawText(QPoint(2 * wm.padding + wm.iconSize, bottom_y), userName);
-
-                // We show the last message timestamp.
-                p.save();
-                if (isPressed_) {
-                        p.setPen(QPen(highlightedTimestampColor_));
-                } else if (underMouse()) {
-                        p.setPen(QPen(hoverTimestampColor_));
-                } else {
-                        p.setPen(QPen(timestampColor_));
-                }
-
-                // p.setFont(tsFont);
-                // p.drawText(QPoint(width() - wm.padding - msgStampWidth, top_y), "timestamp");
-                p.restore();
-        }
-
-        p.setPen(Qt::NoPen);
-
-        if (unreadMsgCount_ > 0) {
-                QBrush brush;
-                brush.setStyle(Qt::SolidPattern);
-
-                brush.setColor(mentionedColor());
-
-                if (isPressed_)
-                        brush.setColor(bubbleFgColor());
-
-                p.setBrush(brush);
-                p.setPen(Qt::NoPen);
-                p.setFont(unreadCountFont_);
-
-                // Extra space on the x-axis to accomodate the extra character space
-                // inside the bubble.
-                const int x_width = unreadMsgCount_ > MaxUnreadCountDisplayed
-                                      ? QFontMetrics(p.font()).averageCharWidth()
-                                      : 0;
-
-                QRectF r(width() - bubbleDiameter_ - wm.padding - x_width,
-                         bottom_y - bubbleDiameter_ / 2 - 5,
-                         bubbleDiameter_ + x_width,
-                         bubbleDiameter_);
-
-                if (width() == sidebarSizes.small)
-                        r = QRectF(width() - bubbleDiameter_ - 5,
-                                   height() - bubbleDiameter_ - 5,
-                                   bubbleDiameter_ + x_width,
-                                   bubbleDiameter_);
-
-                p.setPen(Qt::NoPen);
-                p.drawEllipse(r);
-
-                p.setPen(QPen(bubbleFgColor()));
-
-                if (isPressed_)
-                        p.setPen(QPen(bubbleBgColor()));
-
-                auto countTxt = unreadMsgCount_ > MaxUnreadCountDisplayed
-                                  ? QString("99+")
-                                  : QString::number(unreadMsgCount_);
-
-                p.setBrush(Qt::NoBrush);
-                p.drawText(r.translated(0, -0.5), Qt::AlignCenter, countTxt);
-        }
-
-        if (!isPressed_ && hasUnreadMessages_) {
-                QPen pen;
-                pen.setWidth(wm.unreadLineWidth);
-                pen.setColor(highlightedBackgroundColor_);
-
-                p.setPen(pen);
-                p.drawLine(0, wm.unreadLineOffset, 0, height() - wm.unreadLineOffset);
-        }
-}
\ No newline at end of file
diff --git a/src/UserMentionsWidget.h b/src/UserMentionsWidget.h
deleted file mode 100644
index 179f002688a479a2557f0a82ddabb11dcf03f3fe..0000000000000000000000000000000000000000
--- a/src/UserMentionsWidget.h
+++ /dev/null
@@ -1,164 +0,0 @@
-#pragma once
-
-#include <QColor>
-#include <QHBoxLayout>
-#include <QLabel>
-#include <QLayout>
-#include <QWidget>
-
-class FlatButton;
-class RippleOverlay;
-
-class UserMentionsWidget : public QWidget
-{
-        Q_OBJECT
-
-        Q_PROPERTY(QColor borderColor READ borderColor WRITE setBorderColor)
-
-        Q_PROPERTY(QColor highlightedBackgroundColor READ highlightedBackgroundColor WRITE
-                     setHighlightedBackgroundColor)
-        Q_PROPERTY(
-          QColor hoverBackgroundColor READ hoverBackgroundColor WRITE setHoverBackgroundColor)
-        Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor)
-
-        Q_PROPERTY(QColor avatarBgColor READ avatarBgColor WRITE setAvatarBgColor)
-        Q_PROPERTY(QColor avatarFgColor READ avatarFgColor WRITE setAvatarFgColor)
-
-        Q_PROPERTY(QColor bubbleBgColor READ bubbleBgColor WRITE setBubbleBgColor)
-        Q_PROPERTY(QColor bubbleFgColor READ bubbleFgColor WRITE setBubbleFgColor)
-
-        Q_PROPERTY(QColor titleColor READ titleColor WRITE setTitleColor)
-        Q_PROPERTY(QColor subtitleColor READ subtitleColor WRITE setSubtitleColor)
-
-        Q_PROPERTY(QColor timestampColor READ timestampColor WRITE setTimestampColor)
-        Q_PROPERTY(QColor highlightedTimestampColor READ highlightedTimestampColor WRITE
-                     setHighlightedTimestampColor)
-        Q_PROPERTY(QColor hoverTimestampColor READ hoverTimestampColor WRITE setHoverTimestampColor)
-
-        Q_PROPERTY(
-          QColor highlightedTitleColor READ highlightedTitleColor WRITE setHighlightedTitleColor)
-        Q_PROPERTY(QColor highlightedSubtitleColor READ highlightedSubtitleColor WRITE
-                     setHighlightedSubtitleColor)
-
-        Q_PROPERTY(QColor hoverTitleColor READ hoverTitleColor WRITE setHoverTitleColor)
-        Q_PROPERTY(QColor hoverSubtitleColor READ hoverSubtitleColor WRITE setHoverSubtitleColor)
-
-        Q_PROPERTY(QColor mentionedColor READ mentionedColor WRITE setMentionedColor)
-        Q_PROPERTY(QColor btnColor READ btnColor WRITE setBtnColor)
-        Q_PROPERTY(QColor btnTextColor READ btnTextColor WRITE setBtnTextColor)
-
-public:
-        UserMentionsWidget(QWidget *parent = 0);
-
-        void updateUnreadMessageCount(int count);
-        void clearUnreadMessageCount() { updateUnreadMessageCount(0); };
-        bool isPressed() const { return isPressed_; }
-        int unreadMessageCount() const { return unreadMsgCount_; }
-        QColor borderColor() const { return borderColor_; }
-        void setBorderColor(QColor &color) { borderColor_ = color; }
-        QColor highlightedBackgroundColor() const { return highlightedBackgroundColor_; }
-        QColor hoverBackgroundColor() const { return hoverBackgroundColor_; }
-        QColor hoverTitleColor() const { return hoverTitleColor_; }
-        QColor hoverSubtitleColor() const { return hoverSubtitleColor_; }
-        QColor hoverTimestampColor() const { return hoverTimestampColor_; }
-        QColor backgroundColor() const { return backgroundColor_; }
-        QColor avatarBgColor() const { return avatarBgColor_; }
-        QColor avatarFgColor() const { return avatarFgColor_; }
-
-        QColor highlightedTitleColor() const { return highlightedTitleColor_; }
-        QColor highlightedSubtitleColor() const { return highlightedSubtitleColor_; }
-        QColor highlightedTimestampColor() const { return highlightedTimestampColor_; }
-
-        QColor titleColor() const { return titleColor_; }
-        QColor subtitleColor() const { return subtitleColor_; }
-        QColor timestampColor() const { return timestampColor_; }
-        QColor btnColor() const { return btnColor_; }
-        QColor btnTextColor() const { return btnTextColor_; }
-
-        QColor bubbleFgColor() const { return bubbleFgColor_; }
-        QColor bubbleBgColor() const { return bubbleBgColor_; }
-        QColor mentionedColor() const { return mentionedFontColor_; }
-
-        void setHighlightedBackgroundColor(QColor &color) { highlightedBackgroundColor_ = color; }
-        void setHoverBackgroundColor(QColor &color) { hoverBackgroundColor_ = color; }
-        void setHoverSubtitleColor(QColor &color) { hoverSubtitleColor_ = color; }
-        void setHoverTitleColor(QColor &color) { hoverTitleColor_ = color; }
-        void setHoverTimestampColor(QColor &color) { hoverTimestampColor_ = color; }
-        void setBackgroundColor(QColor &color) { backgroundColor_ = color; }
-        void setTimestampColor(QColor &color) { timestampColor_ = color; }
-        void setAvatarFgColor(QColor &color) { avatarFgColor_ = color; }
-        void setAvatarBgColor(QColor &color) { avatarBgColor_ = color; }
-
-        void setHighlightedTitleColor(QColor &color) { highlightedTitleColor_ = color; }
-        void setHighlightedSubtitleColor(QColor &color) { highlightedSubtitleColor_ = color; }
-        void setHighlightedTimestampColor(QColor &color) { highlightedTimestampColor_ = color; }
-
-        void setTitleColor(QColor &color) { titleColor_ = color; }
-        void setSubtitleColor(QColor &color) { subtitleColor_ = color; }
-
-        void setBtnColor(QColor &color) { btnColor_ = color; }
-        void setBtnTextColor(QColor &color) { btnTextColor_ = color; }
-
-        void setBubbleFgColor(QColor &color) { bubbleFgColor_ = color; }
-        void setBubbleBgColor(QColor &color) { bubbleBgColor_ = color; }
-        void setMentionedColor(QColor &color) { mentionedFontColor_ = color; }
-
-signals:
-        void clicked();
-
-public slots:
-        void setPressedState(bool state);
-
-protected:
-        void mousePressEvent(QMouseEvent *event) override;
-        void paintEvent(QPaintEvent *event) override;
-        void resizeEvent(QResizeEvent *event) override;
-
-private:
-        void init(QWidget *parent);
-
-        RippleOverlay *ripple_overlay_;
-
-        bool isPressed_ = false;
-
-        bool hasUnreadMessages_ = true;
-
-        int unreadMsgCount_ = 0;
-
-        QHBoxLayout *topLayout_;
-
-        QColor borderColor_;
-        QColor highlightedBackgroundColor_;
-        QColor hoverBackgroundColor_;
-        QColor backgroundColor_;
-
-        QColor highlightedTitleColor_;
-        QColor highlightedSubtitleColor_;
-
-        QColor titleColor_;
-        QColor subtitleColor_;
-
-        QColor hoverTitleColor_;
-        QColor hoverSubtitleColor_;
-
-        QColor btnColor_;
-        QColor btnTextColor_;
-
-        QRectF acceptBtnRegion_;
-        QRectF declineBtnRegion_;
-
-        // Fonts
-        QColor mentionedFontColor_;
-        QFont unreadCountFont_;
-        int bubbleDiameter_;
-
-        QColor timestampColor_;
-        QColor highlightedTimestampColor_;
-        QColor hoverTimestampColor_;
-
-        QColor avatarBgColor_;
-        QColor avatarFgColor_;
-
-        QColor bubbleBgColor_;
-        QColor bubbleFgColor_;
-};
\ No newline at end of file
diff --git a/src/dialogs/UserMentions.cpp b/src/popups/UserMentions.cpp
similarity index 95%
rename from src/dialogs/UserMentions.cpp
rename to src/popups/UserMentions.cpp
index f087480994dd7ea5262dfed903f53bc71155f298..77e5260e78a0c6261e18fbdf451bcc557529520b 100644
--- a/src/dialogs/UserMentions.cpp
+++ b/src/popups/UserMentions.cpp
@@ -4,7 +4,7 @@
 #include "UserMentions.h"
 #include "timeline/TimelineItem.h"
 
-using namespace dialogs;
+using namespace popups;
 
 UserMentions::UserMentions(QWidget *parent)
   : QWidget{parent}
@@ -57,6 +57,13 @@ UserMentions::UserMentions(QWidget *parent)
         setLayout(top_layout_);
 }
 
+void
+UserMentions::initializeMentions(const std::map<QString, mtx::responses::Notifications> &notifs)
+{
+        Q_UNUSED(notifs);
+        // Very TODO:
+}
+
 void
 UserMentions::pushItem(const QString &event_id,
                        const QString &user_id,
diff --git a/src/dialogs/UserMentions.h b/src/popups/UserMentions.h
similarity index 82%
rename from src/dialogs/UserMentions.h
rename to src/popups/UserMentions.h
index 9b43dcfda41f7718b97984d068c0d0d342044f6e..5dc475bf599bbbc253c44a2f51483f9227daeba5 100644
--- a/src/dialogs/UserMentions.h
+++ b/src/popups/UserMentions.h
@@ -1,12 +1,15 @@
 #pragma once
 
+#include <mtx/responses.hpp>
+
 #include <QScrollArea>
 #include <QScrollBar>
+#include <QString>
 #include <QTabWidget>
 #include <QVBoxLayout>
 #include <QWidget>
 
-namespace dialogs {
+namespace popups {
 
 class UserMentions : public QWidget
 {
@@ -19,6 +22,8 @@ public:
                       const QString &room_id,
                       const QString &current_room_id);
 
+        void initializeMentions(const std::map<QString, mtx::responses::Notifications> &notifs);
+
 private:
         QTabWidget *tab_layout_;
         QVBoxLayout *top_layout_;